| Title: | Sparse and Dense Matrix Classes and Methods |
|---|---|
| Description: | A rich hierarchy of sparse and dense matrix classes, including general, symmetric, triangular, and diagonal matrices with numeric, logical, or pattern entries. Efficient methods for operating on such matrices, often wrapping the 'BLAS', 'LAPACK', and 'SuiteSparse' libraries. |
| Authors: | Douglas Bates [aut] (ORCID: <https://orcid.org/0000-0001-8316-9503>), Martin Maechler [aut, cre] (ORCID: <https://orcid.org/0000-0002-8685-9910>), Mikael Jagan [aut] (ORCID: <https://orcid.org/0000-0002-3542-2938>), Timothy A. Davis [ctb] (ORCID: <https://orcid.org/0000-0001-7614-6899>, SuiteSparse libraries, collaborators listed in dir(system.file("doc", "SuiteSparse", package="Matrix"), pattern="License", full.names=TRUE, recursive=TRUE)), George Karypis [ctb] (ORCID: <https://orcid.org/0000-0003-2753-1437>, METIS library, Copyright: Regents of the University of Minnesota), Jason Riedy [ctb] (ORCID: <https://orcid.org/0000-0002-4345-4200>, GNU Octave's condest() and onenormest(), Copyright: Regents of the University of California), Jens Oehlschlägel [ctb] (initial nearPD()), R Core Team [ctb] (ROR: <https://ror.org/02zz1nj61>, base R's matrix implementation) |
| Maintainer: | Martin Maechler <[email protected]> |
| License: | GPL (>= 2) | file LICENCE |
| Version: | 1.8-0 |
| Built: | 2026-05-28 14:36:22 UTC |
| Source: | https://github.com/r-forge/matrix |
TODO.
Matrix.Version()Matrix.Version()
(Mv <- Matrix.Version()) stopifnot(identical(Mv[["package"]], utils::packageVersion("Matrix")))(Mv <- Matrix.Version()) stopifnot(identical(Mv[["package"]], utils::packageVersion("Matrix")))
The "abIndex" class, short for “Abstract
Index Vector”, is used for dealing with large index vectors more
efficiently, than using integer (or numeric) vectors of
the kind 2:1000000 or c(0:1e5, 1000:1e6).
Note that the current implementation details are subject to change,
and if you consider working with these classes, please contact the
package maintainers (packageDescription("Matrix")$Maintainer).
Objects can be created by calls of the form new("abIndex", ...),
but more easily and typically either by as(x, "abIndex") where
x is an integer (valued) vector, or directly by
abIseq() and combination c(...) of such.
kind:a character string,
one of ("int32", "double", "rleDiff"), denoting the
internal structure of the abIndex object.
x:Object of class "numLike"; is
used (i.e., not of length 0) only iff the object is not
compressed, i.e., currently exactly when kind != "rleDiff".
rleD:signature(x = "abIndex"): ...
signature(x = "abIndex", i = "index", j = "ANY", drop = "ANY"): ...
signature(from = "numeric", to = "abIndex"): ...
signature(from = "abIndex", to = "numeric"): ...
signature(from = "abIndex", to = "integer"): ...
signature(x = "abIndex"): ...
signature(e1 = "numeric", e2 = "abIndex"): These
and the following arithmetic and logic operations are
not yet implemented; see Ops for a
list of these (S4) group methods.
signature(e1 = "abIndex", e2 = "abIndex"): ...
signature(e1 = "abIndex", e2 = "numeric"): ...
signature(x = "abIndex"): ...
("abIndex"): simple show method,
building on show(<rleDiff>).
("abIndex"): works analogously to regular vectors.
("abIndex"): ditto.
This is currently experimental and not yet used for our own code.
Please contact us (packageDescription("Matrix")$Maintainer),
if you plan to make use of this class.
Partly builds on ideas and code from Jens Oehlschlaegel, as implemented (around 2008, in the GPL'ed part of) package ff.
rle (base) which is used here;
numeric
showClass("abIndex") ii <- c(-3:40, 20:70) str(ai <- as(ii, "abIndex"))# note ai # -> show() method stopifnot(identical(-3:20, as(abIseq1(-3,20), "vector")))showClass("abIndex") ii <- c(-3:40, 20:70) str(ai <- as(ii, "abIndex"))# note ai # -> show() method stopifnot(identical(-3:20, as(abIseq1(-3,20), "vector")))
Generation of abstract index vectors, i.e., objects of class
"abIndex".
abIseq() is designed to work entirely like seq,
but producing "abIndex" vectors.abIseq1() is its basic building block, where
abIseq1(n,m) corresponds to n:m.
c(x, ...) will return an "abIndex" vector, when x
is one.
abIseq1(from = 1, to = 1) abIseq (from = 1, to = 1, by = ((to - from)/(length.out - 1)), length.out = NULL, along.with = NULL) ## S3 method for class 'abIndex' c(...)abIseq1(from = 1, to = 1) abIseq (from = 1, to = 1, by = ((to - from)/(length.out - 1)), length.out = NULL, along.with = NULL) ## S3 method for class 'abIndex' c(...)
from, to
|
the starting and (maximal) end value of the sequence. |
by |
number: increment of the sequence. |
length.out |
desired length of the sequence. A
non-negative number, which for |
along.with |
take the length from the length of this argument. |
... |
in general an arbitrary number of R objects; here,
when the first is an |
An abstract index vector, i.e., object of class
"abIndex".
the class abIndex documentation;
rep2abI() for another constructor;
rle (base).
stopifnot(identical(-3:20, as(abIseq1(-3,20), "vector"))) try( ## (arithmetic) not yet implemented abIseq(1, 50, by = 3) )stopifnot(identical(-3:20, as(abIseq1(-3,20), "vector"))) try( ## (arithmetic) not yet implemented abIseq(1, 50, by = 3) )
Methods for function all.equal() (from R package
base) are defined for all Matrix classes.
\
\
these three methods are
simply using all.equal.numeric directly and work via
as.vector().
There are more methods, notably also for
"sparseVector"'s, see showMethods("all.equal").
showMethods("all.equal") (A <- spMatrix(3,3, i= c(1:3,2:1), j=c(3:1,1:2), x = 1:5)) ex <- expand(lu. <- lu(A)) stopifnot( all.equal(as(A[lu.@p + 1L, lu.@q + 1L], "CsparseMatrix"), lu.@L %*% lu.@U), with(ex, all.equal(as(P %*% A %*% t(Q), "CsparseMatrix"), L %*% U)), with(ex, all.equal(as(A, "CsparseMatrix"), t(P) %*% L %*% U %*% Q)))showMethods("all.equal") (A <- spMatrix(3,3, i= c(1:3,2:1), j=c(3:1,1:2), x = 1:5)) ex <- expand(lu. <- lu(A)) stopifnot( all.equal(as(A[lu.@p + 1L, lu.@q + 1L], "CsparseMatrix"), lu.@L %*% lu.@U), with(ex, all.equal(as(P %*% A %*% t(Q), "CsparseMatrix"), L %*% U)), with(ex, all.equal(as(A, "CsparseMatrix"), t(P) %*% L %*% U %*% Q)))
Detect or standardize a TsparseMatrix with
unsorted or duplicated pairs.
anyDuplicatedT(x, ...) isUniqueT(x, byrow = FALSE, isT = is(x, "TsparseMatrix")) asUniqueT(x, byrow = FALSE, isT = is(x, "TsparseMatrix")) aggregateT(x)anyDuplicatedT(x, ...) isUniqueT(x, byrow = FALSE, isT = is(x, "TsparseMatrix")) asUniqueT(x, byrow = FALSE, isT = is(x, "TsparseMatrix")) aggregateT(x)
x |
an R object. |
... |
optional arguments passed to the default method for
generic function |
byrow |
a logical indicating if |
isT |
a logical indicating if |
anyDuplicatedT(x) returns the index of the first duplicated
pair in x (0 if there are no duplicated pairs).
isUniqueT(x) returns TRUE if x is a
TsparseMatrix with sorted, nonduplicated
pairs and FALSE otherwise.
asUniqueT(x) returns the unique
TsparseMatrix representation of x with
sorted, nonduplicated pairs. Values corresponding to
identical pairs are aggregated by addition, where in the
logical case “addition” refers to logical OR.
aggregateT(x) aggregates without sorting.
Virtual class TsparseMatrix.
example("dgTMatrix-class", echo=FALSE) ## -> 'T2' with (i,j,x) slots of length 5 each T2u <- asUniqueT(T2) stopifnot(## They "are" the same (and print the same): all.equal(T2, T2u, tol=0), ## but not internally: anyDuplicatedT(T2) == 2, anyDuplicatedT(T2u) == 0, length(T2 @x) == 5, length(T2u@x) == 3) isUniqueT(T2 ) # FALSE isUniqueT(T2u) # TRUE T3 <- T2u T3[1, c(1,3)] <- 10; T3[2, c(1,5)] <- 20 T3u <- asUniqueT(T3) str(T3u) # sorted in 'j', and within j, sorted in i stopifnot(isUniqueT(T3u)) ## Logical l.TMatrix and n.TMatrix : (L2 <- T2 > 0) validObject(L2u <- asUniqueT(L2)) (N2 <- as(L2, "nMatrix")) validObject(N2u <- asUniqueT(N2)) stopifnot(N2u@i == L2u@i, L2u@i == T2u@i, N2@i == L2@i, L2@i == T2@i, N2u@j == L2u@j, L2u@j == T2u@j, N2@j == L2@j, L2@j == T2@j) # now with a nasty NA [partly failed in Matrix 1.1-5]: L.0N <- L.1N <- L2 L.0N@x[1:2] <- c(FALSE, NA) L.1N@x[1:2] <- c(TRUE, NA) validObject(L.0N) validObject(L.1N) (m.0N <- as.matrix(L.0N)) (m.1N <- as.matrix(L.1N)) stopifnot(identical(10L, which(is.na(m.0N))), !anyNA(m.1N)) symnum(m.0N) symnum(m.1N)example("dgTMatrix-class", echo=FALSE) ## -> 'T2' with (i,j,x) slots of length 5 each T2u <- asUniqueT(T2) stopifnot(## They "are" the same (and print the same): all.equal(T2, T2u, tol=0), ## but not internally: anyDuplicatedT(T2) == 2, anyDuplicatedT(T2u) == 0, length(T2 @x) == 5, length(T2u@x) == 3) isUniqueT(T2 ) # FALSE isUniqueT(T2u) # TRUE T3 <- T2u T3[1, c(1,3)] <- 10; T3[2, c(1,5)] <- 20 T3u <- asUniqueT(T3) str(T3u) # sorted in 'j', and within j, sorted in i stopifnot(isUniqueT(T3u)) ## Logical l.TMatrix and n.TMatrix : (L2 <- T2 > 0) validObject(L2u <- asUniqueT(L2)) (N2 <- as(L2, "nMatrix")) validObject(N2u <- asUniqueT(N2)) stopifnot(N2u@i == L2u@i, L2u@i == T2u@i, N2@i == L2@i, L2@i == T2@i, N2u@j == L2u@j, L2u@j == T2u@j, N2@j == L2@j, L2@j == T2@j) # now with a nasty NA [partly failed in Matrix 1.1-5]: L.0N <- L.1N <- L2 L.0N@x[1:2] <- c(FALSE, NA) L.1N@x[1:2] <- c(TRUE, NA) validObject(L.0N) validObject(L.1N) (m.0N <- as.matrix(L.0N)) (m.1N <- as.matrix(L.1N)) stopifnot(identical(10L, which(is.na(m.0N))), !anyNA(m.1N)) symnum(m.0N) symnum(m.1N)
Return the matrix obtained by setting to zero elements below a diagonal
(triu), above a diagonal (tril), or outside of a general
band (band).
band(x, k1, k2, ...) triu(x, k = 0L, ...) tril(x, k = 0L, ...)band(x, k1, k2, ...) triu(x, k = 0L, ...) tril(x, k = 0L, ...)
x |
a matrix-like object |
k, k1, k2
|
integers specifying the diagonals that are not set to
zero, |
... |
optional arguments passed to methods, currently unused by package Matrix. |
triu(x, k) is equivalent to band(x, k, dim(x)[2]).
Similarly,
tril(x, k) is equivalent to band(x, -dim(x)[1], k).
An object of a suitable matrix class, inheriting from
triangularMatrix where appropriate.
It inherits from sparseMatrix if
and only if x does.
method for compressed, sparse, column-oriented matrices.
method for compressed, sparse, row-oriented matrices.
method for sparse matrices in triplet format.
method for diagonal matrices.
method for dense matrices in packed or unpacked format.
method for traditional matrices
of implicit class matrix.
bandSparse for the construction of a
banded sparse matrix directly from its non-zero diagonals.
## A random sparse matrix : set.seed(7) m <- matrix(0, 5, 5) m[sample(length(m), size = 14)] <- rep(1:9, length=14) (mm <- as(m, "CsparseMatrix")) tril(mm) # lower triangle tril(mm, -1) # strict lower triangle triu(mm, 1) # strict upper triangle band(mm, -1, 2) # general band (m5 <- Matrix(rnorm(25), ncol = 5)) tril(m5) # lower triangle tril(m5, -1) # strict lower triangle triu(m5, 1) # strict upper triangle band(m5, -1, 2) # general band (m65 <- Matrix(rnorm(30), ncol = 5)) # not square triu(m65) # result not "dtrMatrix" unless square (sm5 <- crossprod(m65)) # symmetric band(sm5, -1, 1)# "dsyMatrix": symmetric band preserves symmetry property as(band(sm5, -1, 1), "sparseMatrix")# often preferable (sm <- round(crossprod(triu(mm/2)))) # sparse symmetric ("dsC*") band(sm, -1,1) # remains "dsC", *however* band(sm, -2,1) # -> "dgC"## A random sparse matrix : set.seed(7) m <- matrix(0, 5, 5) m[sample(length(m), size = 14)] <- rep(1:9, length=14) (mm <- as(m, "CsparseMatrix")) tril(mm) # lower triangle tril(mm, -1) # strict lower triangle triu(mm, 1) # strict upper triangle band(mm, -1, 2) # general band (m5 <- Matrix(rnorm(25), ncol = 5)) tril(m5) # lower triangle tril(m5, -1) # strict lower triangle triu(m5, 1) # strict upper triangle band(m5, -1, 2) # general band (m65 <- Matrix(rnorm(30), ncol = 5)) # not square triu(m65) # result not "dtrMatrix" unless square (sm5 <- crossprod(m65)) # symmetric band(sm5, -1, 1)# "dsyMatrix": symmetric band preserves symmetry property as(band(sm5, -1, 1), "sparseMatrix")# often preferable (sm <- round(crossprod(triu(mm/2)))) # sparse symmetric ("dsC*") band(sm, -1,1) # remains "dsC", *however* band(sm, -2,1) # -> "dgC"
Construct a sparse banded matrix by specifying its non-zero sup- and super-diagonals.
bandSparse(n, m = n, k, diagonals, symmetric = FALSE, repr = "C", giveCsparse = (repr == "C"), int2dbl = )bandSparse(n, m = n, k, diagonals, symmetric = FALSE, repr = "C", giveCsparse = (repr == "C"), int2dbl = )
n, m
|
the matrix dimension |
k |
integer vector of “diagonal numbers”, with identical
meaning as in |
diagonals |
optional list of sub-/super- diagonals; if missing,
the result will be a pattern matrix, i.e., inheriting from
class
|
symmetric |
logical; if true the result will be symmetric
(inheriting from class |
repr |
|
giveCsparse |
(deprecated, replaced with |
int2dbl |
|
a sparse matrix (of class
CsparseMatrix) of dimension
with diagonal “bands” as specified.
band, for extraction of matrix bands;
bdiag, diag,
sparseMatrix,
Matrix.
diags <- list(1:30, 10*(1:20), 100*(1:20)) s1 <- bandSparse(13, k = -c(0:2, 6), diag = c(diags, diags[2]), symm=TRUE) s1 s2 <- bandSparse(13, k = c(0:2, 6), diag = c(diags, diags[2]), symm=TRUE) stopifnot(identical(s1, t(s2)), is(s1,"dsCMatrix")) ## a pattern Matrix of *full* (sub-)diagonals: bk <- c(0:4, 7,9) (s3 <- bandSparse(30, k = bk, symm = TRUE)) ## If you want a pattern matrix, but with "sparse"-diagonals, ## you currently need to go via logical sparse: lLis <- lapply(list(rpois(20, 2), rpois(20, 1), rpois(20, 3))[c(1:3, 2:3, 3:2)], as.logical) (s4 <- bandSparse(20, k = bk, symm = TRUE, diag = lLis)) (s4. <- as(drop0(s4), "nsparseMatrix")) n <- 1e4 bk <- c(0:5, 7,11) bMat <- matrix(1:8, n, 8, byrow=TRUE) bLis <- as.data.frame(bMat) B <- bandSparse(n, k = bk, diag = bLis) Bs <- bandSparse(n, k = bk, diag = bLis, symmetric=TRUE) B [1:15, 1:30] Bs[1:15, 1:30] ## can use a list *or* a matrix for specifying the diagonals: stopifnot(identical(B, bandSparse(n, k = bk, diag = bMat)), identical(Bs, bandSparse(n, k = bk, diag = bMat, symmetric=TRUE)) , inherits(B, "dtCMatrix") # triangular! )diags <- list(1:30, 10*(1:20), 100*(1:20)) s1 <- bandSparse(13, k = -c(0:2, 6), diag = c(diags, diags[2]), symm=TRUE) s1 s2 <- bandSparse(13, k = c(0:2, 6), diag = c(diags, diags[2]), symm=TRUE) stopifnot(identical(s1, t(s2)), is(s1,"dsCMatrix")) ## a pattern Matrix of *full* (sub-)diagonals: bk <- c(0:4, 7,9) (s3 <- bandSparse(30, k = bk, symm = TRUE)) ## If you want a pattern matrix, but with "sparse"-diagonals, ## you currently need to go via logical sparse: lLis <- lapply(list(rpois(20, 2), rpois(20, 1), rpois(20, 3))[c(1:3, 2:3, 3:2)], as.logical) (s4 <- bandSparse(20, k = bk, symm = TRUE, diag = lLis)) (s4. <- as(drop0(s4), "nsparseMatrix")) n <- 1e4 bk <- c(0:5, 7,11) bMat <- matrix(1:8, n, 8, byrow=TRUE) bLis <- as.data.frame(bMat) B <- bandSparse(n, k = bk, diag = bLis) Bs <- bandSparse(n, k = bk, diag = bLis, symmetric=TRUE) B [1:15, 1:30] Bs[1:15, 1:30] ## can use a list *or* a matrix for specifying the diagonals: stopifnot(identical(B, bandSparse(n, k = bk, diag = bMat)), identical(Bs, bandSparse(n, k = bk, diag = bMat, symmetric=TRUE)) , inherits(B, "dtCMatrix") # triangular! )
Build a block diagonal matrix given several building block matrices.
bdiag(..., int2dbl = ) .bdiag(lst, int2dbl = )bdiag(..., int2dbl = ) .bdiag(lst, int2dbl = )
... |
individual matrices or a |
lst |
non-empty |
int2dbl |
|
For non-trivial argument list, bdiag() calls .bdiag().
The latter maybe useful to programmers.
A sparse matrix obtained by combining the arguments into a block diagonal matrix.
The value of bdiag() inherits from class
CsparseMatrix, whereas
.bdiag() returns a TsparseMatrix.
This function has been written and is efficient for the case of relatively few block matrices which are typically sparse themselves.
It is currently inefficient for the case of many small dense
block matrices.
For the case of many dense matrices,
the bdiag_m() function in the ‘Examples’ is an order of
magnitude faster.
Martin Maechler, built on a version posted by Berton Gunter to
R-help; earlier versions have been posted by other authors, notably
Scott Chasalow to S-news. Doug Bates's faster implementation builds
on TsparseMatrix objects.
Diagonal for constructing matrices of
class diagonalMatrix, or kronecker
which also works for "Matrix" inheriting matrices.
bandSparse constructs a banded sparse matrix from
its non-zero sub-/super - diagonals.
Note that other CRAN R packages have own versions of bdiag()
which return traditional matrices.
bdiag(matrix(1:4, 2), diag(3)) ## combine "Matrix" class and traditional matrices: bdiag(Diagonal(2), matrix(1:3, 3,4), diag(3:2)) mlist <- list(1, 2:3, diag(x=5:3), 27, cbind(1,3:6), 100:101) bdiag(mlist) stopifnot(identical(bdiag(mlist), bdiag(lapply(mlist, as.matrix)))) ml <- c(as(matrix((1:24)%% 11 == 0, 6,4),"nMatrix"), rep(list(Diagonal(2, x=TRUE)), 3)) mln <- c(ml, Diagonal(x = 1:3, int2dbl = FALSE)) sapply(mln, class) # "ngCMatrix" "ldi*" .. "idiMatrix" stopifnot(is(bdiag(ml), "lsparseMatrix"), is(bdiag(mln, int2dbl = FALSE),"isparseMatrix") ) ## random (diagonal-)block-triangular matrices: rblockTri <- function(nb, max.ni, lambda = 3) { .bdiag(replicate(nb, { n <- sample.int(max.ni, 1) tril(Matrix(rpois(n * n, lambda = lambda), n, n)) })) } (T4 <- rblockTri(4, 10, lambda = 1)) image(T1 <- rblockTri(12, 20)) ##' Fast version of Matrix :: .bdiag() -- for the case of *many* (k x k) matrices: ##' @param lmat list(<mat1>, <mat2>, ....., <mat_N>) where each mat_j is a k x k 'matrix' ##' @return a sparse (N*k x N*k) matrix of class \code{"\linkS4class{dgCMatrix}"}. bdiag_m <- function(lmat) { ## Copyright (C) 2016 Martin Maechler, ETH Zurich if(!length(lmat)) return(new("dgCMatrix")) stopifnot(is.list(lmat), is.matrix(lmat[[1]]), (k <- (d <- dim(lmat[[1]]))[1]) == d[2], # k x k all(vapply(lmat, dim, integer(2)) == k)) # all of them N <- length(lmat) if(N * k > .Machine$integer.max) stop("resulting matrix too large; would be M x M, with M=", N*k) M <- as.integer(N * k) ## result: an M x M matrix new("dgCMatrix", Dim = c(M,M), ## 'i :' maybe there's a faster way (w/o matrix indexing), but elegant? i = as.vector(matrix(0L:(M-1L), nrow=k)[, rep(seq_len(N), each=k)]), p = k * 0L:M, x = as.double(unlist(lmat, recursive=FALSE, use.names=FALSE))) } l12 <- replicate(12, matrix(rpois(16, lambda = 6.4), 4, 4), simplify=FALSE) dim(T12 <- bdiag_m(l12))# 48 x 48 T12[1:20, 1:20]bdiag(matrix(1:4, 2), diag(3)) ## combine "Matrix" class and traditional matrices: bdiag(Diagonal(2), matrix(1:3, 3,4), diag(3:2)) mlist <- list(1, 2:3, diag(x=5:3), 27, cbind(1,3:6), 100:101) bdiag(mlist) stopifnot(identical(bdiag(mlist), bdiag(lapply(mlist, as.matrix)))) ml <- c(as(matrix((1:24)%% 11 == 0, 6,4),"nMatrix"), rep(list(Diagonal(2, x=TRUE)), 3)) mln <- c(ml, Diagonal(x = 1:3, int2dbl = FALSE)) sapply(mln, class) # "ngCMatrix" "ldi*" .. "idiMatrix" stopifnot(is(bdiag(ml), "lsparseMatrix"), is(bdiag(mln, int2dbl = FALSE),"isparseMatrix") ) ## random (diagonal-)block-triangular matrices: rblockTri <- function(nb, max.ni, lambda = 3) { .bdiag(replicate(nb, { n <- sample.int(max.ni, 1) tril(Matrix(rpois(n * n, lambda = lambda), n, n)) })) } (T4 <- rblockTri(4, 10, lambda = 1)) image(T1 <- rblockTri(12, 20)) ##' Fast version of Matrix :: .bdiag() -- for the case of *many* (k x k) matrices: ##' @param lmat list(<mat1>, <mat2>, ....., <mat_N>) where each mat_j is a k x k 'matrix' ##' @return a sparse (N*k x N*k) matrix of class \code{"\linkS4class{dgCMatrix}"}. bdiag_m <- function(lmat) { ## Copyright (C) 2016 Martin Maechler, ETH Zurich if(!length(lmat)) return(new("dgCMatrix")) stopifnot(is.list(lmat), is.matrix(lmat[[1]]), (k <- (d <- dim(lmat[[1]]))[1]) == d[2], # k x k all(vapply(lmat, dim, integer(2)) == k)) # all of them N <- length(lmat) if(N * k > .Machine$integer.max) stop("resulting matrix too large; would be M x M, with M=", N*k) M <- as.integer(N * k) ## result: an M x M matrix new("dgCMatrix", Dim = c(M,M), ## 'i :' maybe there's a faster way (w/o matrix indexing), but elegant? i = as.vector(matrix(0L:(M-1L), nrow=k)[, rep(seq_len(N), each=k)]), p = k * 0L:M, x = as.double(unlist(lmat, recursive=FALSE, use.names=FALSE))) } l12 <- replicate(12, matrix(rpois(16, lambda = 6.4), 4, 4), simplify=FALSE) dim(T12 <- bdiag_m(l12))# 48 x 48 T12[1:20, 1:20]
The base functions cbind and rbind are
defined for an arbitrary number of arguments and hence have the first
formal argument .... Now, when S4 objects are found among the arguments,
base cbind() and rbind() internally “dispatch”
recursively, calling cbind2 or rbind2
respectively, where these have methods defined and so should dispatch
appropriately.
cbind2() and rbind2() are from the
methods package, i.e., standard R, and have been provided for
binding together two matrices, where in Matrix, we have
defined methods for these and the 'Matrix' matrices.
## cbind(..., deparse.level = 1) ## rbind(..., deparse.level = 1) ## S4 method for signature 'Matrix,Matrix' cbind2(x, y, ...) ## S4 method for signature 'Matrix,Matrix' rbind2(x, y, ...)## cbind(..., deparse.level = 1) ## rbind(..., deparse.level = 1) ## S4 method for signature 'Matrix,Matrix' cbind2(x, y, ...) ## S4 method for signature 'Matrix,Matrix' rbind2(x, y, ...)
... |
for |
deparse.level |
integer controlling the construction of labels
in the case of non-matrix-like arguments; see |
x, y
|
vector- or matrix-like R objects to be bound together. |
typically a ‘matrix-like’ object of a similar
class as the first argument in ....
Note that sometimes by default, the result is a
sparseMatrix if one of the arguments is (even in
the case where this is not efficient). In other cases,
the result is chosen to be sparse when there are more zero entries is
than non-zero ones (as the default sparse in
Matrix()).
Martin Maechler
Our class definition help pages mentioning cbind2() and
rbind2() methods:
"denseMatrix",
"diagonalMatrix",
"indMatrix".
(a <- matrix(c(2:1,1:2), 2,2)) (M1 <- cbind(0, rbind(a, 7))) # a traditional matrix D <- Diagonal(2) (M2 <- cbind(4, a, D, -1, D, 0)) # a sparse Matrix stopifnot(validObject(M2), inherits(M2, "sparseMatrix"), dim(M2) == c(2,9))(a <- matrix(c(2:1,1:2), 2,2)) (M1 <- cbind(0, rbind(a, 7))) # a traditional matrix D <- Diagonal(2) (M2 <- cbind(4, a, D, -1, D, 0)) # a sparse Matrix stopifnot(validObject(M2), inherits(M2, "sparseMatrix"), dim(M2) == c(2,9))
%&% and MethodsFor boolean or “pattern” matrices, i.e., R objects of
class nMatrix, it is natural to allow matrix
products using boolean instead of numerical arithmetic.
In package Matrix, we use the binary operator %&% (aka
“infix”) function) for this and provide methods for all our
matrices and the traditional R matrices (see matrix).
a pattern matrix, i.e., inheriting from "nMatrix",
or an "ldiMatrix" in case of a diagonal matrix.
We provide methods for both the “traditional” (R base) matrices
and numeric vectors and conceptually all matrices and
sparseVectors in package Matrix.
signature(x = "ANY", y = "ANY")signature(x = "ANY", y = "Matrix")signature(x = "Matrix", y = "ANY")signature(x = "nMatrix", y = "nMatrix")signature(x = "nMatrix", y = "nsparseMatrix")signature(x = "nsparseMatrix", y = "nMatrix")signature(x = "nsparseMatrix", y = "nsparseMatrix")signature(x = "sparseVector", y = "sparseVector")These boolean arithmetic matrix products had been newly introduced for Matrix 1.2.0 (March 2015). Its implementation has still not been tested extensively.
Originally, it was left unspecified how non-structural zeros, i.e., 0's
as part of the M@x slot should be treated for numeric
("dMatrix") and logical ("lMatrix")
sparse matrices. We now specify that boolean matrix products should behave as if
applied to drop0(M), i.e., as if dropping such zeros from
the matrix before using it.
Equivalently, for all matrices M, boolean arithmetic should work as if
applied to M != 0 (or M != FALSE).
The current implementation ends up coercing both x and y to
(virtual) class nsparseMatrix which may be quite inefficient
for dense matrices. A future implementation may well return a matrix
with different class, but the “same” content, i.e., the
same matrix entries .
%*%, crossprod(), or tcrossprod(),
for (regular) matrix product methods.
set.seed(7) L <- Matrix(rnorm(20) > 1, 4,5) (N <- as(L, "nMatrix")) L. <- L; L.[1:2,1] <- TRUE; L.@x[1:2] <- FALSE; L. # has "zeros" to drop0() D <- Matrix(round(rnorm(30)), 5,6) # -> values in -1:1 (for this seed) L %&% D stopifnot(identical(L %&% D, N %&% D), all(L %&% D == as((L %*% abs(D)) > 0, "sparseMatrix"))) ## cross products , possibly with boolArith = TRUE : crossprod(N) # -> sparse patter'n' (TRUE/FALSE : boolean arithmetic) crossprod(N +0) # -> numeric Matrix (with same "pattern") stopifnot(all(crossprod(N) == t(N) %&% N), identical(crossprod(N), crossprod(N +0, boolArith=TRUE)), identical(crossprod(L), crossprod(N , boolArith=FALSE))) crossprod(D, boolArith = TRUE) # pattern: "nsCMatrix" crossprod(L, boolArith = TRUE) # ditto crossprod(L, boolArith = FALSE) # numeric: "dsCMatrix"set.seed(7) L <- Matrix(rnorm(20) > 1, 4,5) (N <- as(L, "nMatrix")) L. <- L; L.[1:2,1] <- TRUE; L.@x[1:2] <- FALSE; L. # has "zeros" to drop0() D <- Matrix(round(rnorm(30)), 5,6) # -> values in -1:1 (for this seed) L %&% D stopifnot(identical(L %&% D, N %&% D), all(L %&% D == as((L %*% abs(D)) > 0, "sparseMatrix"))) ## cross products , possibly with boolArith = TRUE : crossprod(N) # -> sparse patter'n' (TRUE/FALSE : boolean arithmetic) crossprod(N +0) # -> numeric Matrix (with same "pattern") stopifnot(all(crossprod(N) == t(N) %&% N), identical(crossprod(N), crossprod(N +0, boolArith=TRUE)), identical(crossprod(L), crossprod(N , boolArith=FALSE))) crossprod(D, boolArith = TRUE) # pattern: "nsCMatrix" crossprod(L, boolArith = TRUE) # ditto crossprod(L, boolArith = FALSE) # numeric: "dsCMatrix"
Computes the Bunch-Kaufman factorization of an
real, symmetric matrix , which has the general form
where
and are symmetric, block diagonal
matrices composed of and
or diagonal blocks;
is the product of row-permuted unit upper triangular
matrices, each having nonzero entries above the diagonal in 1 or 2 columns;
and
is the product of row-permuted unit lower triangular
matrices, each having nonzero entries below the diagonal in 1 or 2 columns.
Methods are built on LAPACK routines dsytrf and dsptrf.
BunchKaufman(x, ...) ## S4 method for signature 'denseMatrix' BunchKaufman(x, warnSing = TRUE, uplo = "U", trans = "C", ...) ## S4 method for signature 'matrix' BunchKaufman(x, ...)BunchKaufman(x, ...) ## S4 method for signature 'denseMatrix' BunchKaufman(x, warnSing = TRUE, uplo = "U", trans = "C", ...) ## S4 method for signature 'matrix' BunchKaufman(x, ...)
x |
a finite symmetric matrix or
|
warnSing |
a logical indicating if a warning should
be signaled for singular |
uplo |
a string, either |
trans |
. |
... |
further arguments passed to or from methods. |
An object representing the factorization, inheriting from
virtual class BunchKaufmanFactorization.
The specific class is BunchKaufman unless
x inherits from virtual class packedMatrix,
in which case it is pBunchKaufman.
The LAPACK source code, including documentation; see https://netlib.org/lapack/double/dsytrf.f and https://netlib.org/lapack/double/dsptrf.f.
Golub, G. H., & Van Loan, C. F. (2013). Matrix computations (4th ed.). Johns Hopkins University Press. doi:10.56021/9781421407944
Classes BunchKaufman and
pBunchKaufman and their methods.
Classes dsyMatrix and
dspMatrix.
Generic functions expand1 and expand2,
for constructing matrix factors from the result.
Generic functions Cholesky, Schur,
lu, and qr,
for computing other factorizations.
showMethods("BunchKaufman", inherited = FALSE) set.seed(0) data(CAex, package = "Matrix") class(CAex) # dgCMatrix isSymmetric(CAex) # symmetric, but not formally A <- as(CAex, "symmetricMatrix") class(A) # dsCMatrix ## Have methods for denseMatrix (unpacked and packed), ## but not yet sparseMatrix ... ## Not run: (bk.A <- BunchKaufman(A)) ## End(Not run) (bk.A <- BunchKaufman(as(A, "unpackedMatrix"))) ## A ~ U DU U' in floating point str(e.bk.A <- expand2(bk.A), max.level = 2L) stopifnot(all.equal(as(A, "matrix"), as(Reduce(`%*%`, e.bk.A), "matrix")))showMethods("BunchKaufman", inherited = FALSE) set.seed(0) data(CAex, package = "Matrix") class(CAex) # dgCMatrix isSymmetric(CAex) # symmetric, but not formally A <- as(CAex, "symmetricMatrix") class(A) # dsCMatrix ## Have methods for denseMatrix (unpacked and packed), ## but not yet sparseMatrix ... ## Not run: (bk.A <- BunchKaufman(A)) ## End(Not run) (bk.A <- BunchKaufman(as(A, "unpackedMatrix"))) ## A ~ U DU U' in floating point str(e.bk.A <- expand2(bk.A), max.level = 2L) stopifnot(all.equal(as(A, "matrix"), as(Reduce(`%*%`, e.bk.A), "matrix")))
An example of a sparse matrix for which eigen() seemed
to be difficult, an unscaled version of this has been posted to the
web, accompanying an E-mail to R-help
(https://stat.ethz.ch/mailman/listinfo/r-help), by
Casper J Albers, Open University, UK.
data(CAex)data(CAex)
This is a symmetric matrix with 216
non-zero entries in five bands, stored as sparse matrix of class
dgCMatrix.
Historical note (2006-03-30):
In earlier versions of R, eigen(CAex) fell into an
infinite loop whereas eigen(CAex, EISPACK=TRUE) had been okay.
data(CAex, package = "Matrix") str(CAex) # of class "dgCMatrix" image(CAex)# -> it's a simple band matrix with 5 bands ## and the eigen values are basically 1 (42 times) and 0 (30 x): zapsmall(ev <- eigen(CAex, only.values=TRUE)$values) ## i.e., the matrix is symmetric, hence sCA <- as(CAex, "symmetricMatrix") ## and stopifnot(class(sCA) == "dsCMatrix", as(sCA, "matrix") == as(CAex, "matrix"))data(CAex, package = "Matrix") str(CAex) # of class "dgCMatrix" image(CAex)# -> it's a simple band matrix with 5 bands ## and the eigen values are basically 1 (42 times) and 0 (30 x): zapsmall(ev <- eigen(CAex, only.values=TRUE)$values) ## i.e., the matrix is symmetric, hence sCA <- as(CAex, "symmetricMatrix") ## and stopifnot(class(sCA) == "dsCMatrix", as(sCA, "matrix") == as(CAex, "matrix"))
Computes the upper triangular Cholesky factor of an
real, symmetric, positive semidefinite
matrix , optionally after pivoting.
That is the factor in
or (equivalently)
where
is a permutation matrix.
Methods for denseMatrix are built on
LAPACK routines dpstrf, dpotrf, and dpptrf,
The latter two do not permute rows or columns,
so that is an identity matrix.
Methods for sparseMatrix are built on
CHOLMOD routines cholmod_analyze and cholmod_factorize_p.
chol(x, ...) ## S4 method for signature 'denseMatrix' chol(x, pivot = FALSE, tol = -1, ...) ## S4 method for signature 'CsparseMatrix' chol(x, pivot = FALSE, ...)chol(x, ...) ## S4 method for signature 'denseMatrix' chol(x, pivot = FALSE, tol = -1, ...) ## S4 method for signature 'CsparseMatrix' chol(x, pivot = FALSE, ...)
x |
a finite, symmetric, positive
semidefinite matrix or |
pivot |
a logical indicating if the rows and columns
of |
tol |
a finite numeric tolerance,
used only if |
... |
further arguments passed to or from methods. |
For x inheriting from diagonalMatrix,
the diagonal result is computed directly and without pivoting,
i.e., bypassing CHOLMOD.
For all other x, chol(x, pivot = value) calls
Cholesky(x, perm = value, ...) under the hood.
If you must know the permutation in addition
to the Cholesky factor , then call Cholesky
directly, as the result of chol(x, pivot = TRUE) specifies
but not .
A matrix, triangularMatrix,
or diagonalMatrix representing
the upper triangular Cholesky factor .
The result is a traditional matrix if x is a
traditional matrix, dense if x is dense, and
sparse if x is sparse.
The LAPACK source code, including documentation; see https://netlib.org/lapack/double/dpstrf.f, https://netlib.org/lapack/double/dpotrf.f, and https://netlib.org/lapack/double/dpptrf.f.
The CHOLMOD source code; see
https://github.com/DrTimothyAldenDavis/SuiteSparse,
notably the header file ‘CHOLMOD/Include/cholmod.h’
defining cholmod_factor_struct.
Chen, Y., Davis, T. A., Hager, W. W., & Rajamanickam, S. (2008). Algorithm 887: CHOLMOD, supernodal sparse Cholesky factorization and update/downdate. ACM Transactions on Mathematical Software, 35(3), Article 22, 1-14. doi:10.1145/1391989.1391995
Amestoy, P. R., Davis, T. A., & Duff, I. S. (2004). Algorithm 837: AMD, an approximate minimum degree ordering algorithm. ACM Transactions on Mathematical Software, 17(4), 886-905. doi:10.1145/1024074.1024081
Golub, G. H., & Van Loan, C. F. (2013). Matrix computations (4th ed.). Johns Hopkins University Press. doi:10.56021/9781421407944
The default method from base, chol,
called for traditional matrices x.
Generic function Cholesky, for more flexibility
notably when computing the Cholesky factorization and
not only the factor .
showMethods("chol", inherited = FALSE) set.seed(0) ## ---- Dense ---------------------------------------------------------- ## chol(x, pivot = value) wrapping Cholesky(x, perm = value) selectMethod("chol", "dsyMatrix") ## Except in packed cases where pivoting is not yet available selectMethod("chol", "dspMatrix") ## .... Positive definite .............................................. (A1 <- new("dsyMatrix", Dim = c(2L, 2L), x = c(1, 2, 2, 5))) (R1.nopivot <- chol(A1)) (R1 <- chol(A1, pivot = TRUE)) ## In 2-by-2 cases, we know that the permutation is 1:2 or 2:1, ## even if in general 'chol' does not say ... stopifnot(exprs = { all.equal( A1 , as(crossprod(R1.nopivot), "dsyMatrix")) all.equal(t(A1[2:1, 2:1]), as(crossprod(R1 ), "dsyMatrix")) identical(Cholesky(A1)@perm, 2:1) # because 5 > 1 }) ## .... Positive semidefinite but not positive definite ................ (A2 <- new("dpoMatrix", Dim = c(2L, 2L), x = c(1, 2, 2, 4))) try(R2.nopivot <- chol(A2)) # fails as not positive definite (R2 <- chol(A2, pivot = TRUE)) # returns, with a warning and ... stopifnot(exprs = { all.equal(t(A2[2:1, 2:1]), as(crossprod(R2), "dsyMatrix")) identical(Cholesky(A2)@perm, 2:1) # because 4 > 1 }) ## .... Not positive semidefinite ...................................... (A3 <- new("dsyMatrix", Dim = c(2L, 2L), x = c(1, 2, 2, 3))) try(R3.nopivot <- chol(A3)) # fails as not positive definite (R3 <- chol(A3, pivot = TRUE)) # returns, with a warning and ... ## _Not_ equal: see details and examples in help("Cholesky") all.equal(t(A3[2:1, 2:1]), as(crossprod(R3), "dsyMatrix")) ## ---- Sparse --------------------------------------------------------- ## chol(x, pivot = value) wrapping ## Cholesky(x, perm = value, LDL = FALSE, super = FALSE) selectMethod("chol", "dsCMatrix") ## Except in diagonal cases which are handled "directly" selectMethod("chol", "ddiMatrix") (A4 <- toeplitz(as(c(10, 0, 1, 0, 3), "sparseVector"))) (ch.A4.nopivot <- Cholesky(A4, perm = FALSE, LDL = FALSE, super = FALSE)) (ch.A4 <- Cholesky(A4, perm = TRUE, LDL = FALSE, super = FALSE)) (R4.nopivot <- chol(A4)) (R4 <- chol(A4, pivot = TRUE)) det4 <- det(A4) b4 <- rnorm(5L) x4 <- solve(A4, b4) stopifnot(exprs = { identical(R4.nopivot, expand1(ch.A4.nopivot, "L.")) identical(R4, expand1(ch.A4, "L.")) all.equal(A4, as(crossprod(R4.nopivot), "symmetricMatrix")) all.equal(A4[ch.A4@perm + 1L, ch.A4@perm + 1L], as(crossprod(R4 ), "symmetricMatrix")) all.equal(diag(R4.nopivot), sqrt(diag(ch.A4.nopivot))) all.equal(diag(R4), sqrt(diag(ch.A4))) all.equal(sqrt(det4), det(R4.nopivot)) all.equal(sqrt(det4), det(R4)) all.equal(det4, det(ch.A4.nopivot, sqrt = FALSE)) all.equal(det4, det(ch.A4, sqrt = FALSE)) all.equal(x4, solve(R4.nopivot, solve(t(R4.nopivot), b4))) all.equal(x4, solve(ch.A4.nopivot, b4)) all.equal(x4, solve(ch.A4, b4)) })showMethods("chol", inherited = FALSE) set.seed(0) ## ---- Dense ---------------------------------------------------------- ## chol(x, pivot = value) wrapping Cholesky(x, perm = value) selectMethod("chol", "dsyMatrix") ## Except in packed cases where pivoting is not yet available selectMethod("chol", "dspMatrix") ## .... Positive definite .............................................. (A1 <- new("dsyMatrix", Dim = c(2L, 2L), x = c(1, 2, 2, 5))) (R1.nopivot <- chol(A1)) (R1 <- chol(A1, pivot = TRUE)) ## In 2-by-2 cases, we know that the permutation is 1:2 or 2:1, ## even if in general 'chol' does not say ... stopifnot(exprs = { all.equal( A1 , as(crossprod(R1.nopivot), "dsyMatrix")) all.equal(t(A1[2:1, 2:1]), as(crossprod(R1 ), "dsyMatrix")) identical(Cholesky(A1)@perm, 2:1) # because 5 > 1 }) ## .... Positive semidefinite but not positive definite ................ (A2 <- new("dpoMatrix", Dim = c(2L, 2L), x = c(1, 2, 2, 4))) try(R2.nopivot <- chol(A2)) # fails as not positive definite (R2 <- chol(A2, pivot = TRUE)) # returns, with a warning and ... stopifnot(exprs = { all.equal(t(A2[2:1, 2:1]), as(crossprod(R2), "dsyMatrix")) identical(Cholesky(A2)@perm, 2:1) # because 4 > 1 }) ## .... Not positive semidefinite ...................................... (A3 <- new("dsyMatrix", Dim = c(2L, 2L), x = c(1, 2, 2, 3))) try(R3.nopivot <- chol(A3)) # fails as not positive definite (R3 <- chol(A3, pivot = TRUE)) # returns, with a warning and ... ## _Not_ equal: see details and examples in help("Cholesky") all.equal(t(A3[2:1, 2:1]), as(crossprod(R3), "dsyMatrix")) ## ---- Sparse --------------------------------------------------------- ## chol(x, pivot = value) wrapping ## Cholesky(x, perm = value, LDL = FALSE, super = FALSE) selectMethod("chol", "dsCMatrix") ## Except in diagonal cases which are handled "directly" selectMethod("chol", "ddiMatrix") (A4 <- toeplitz(as(c(10, 0, 1, 0, 3), "sparseVector"))) (ch.A4.nopivot <- Cholesky(A4, perm = FALSE, LDL = FALSE, super = FALSE)) (ch.A4 <- Cholesky(A4, perm = TRUE, LDL = FALSE, super = FALSE)) (R4.nopivot <- chol(A4)) (R4 <- chol(A4, pivot = TRUE)) det4 <- det(A4) b4 <- rnorm(5L) x4 <- solve(A4, b4) stopifnot(exprs = { identical(R4.nopivot, expand1(ch.A4.nopivot, "L.")) identical(R4, expand1(ch.A4, "L.")) all.equal(A4, as(crossprod(R4.nopivot), "symmetricMatrix")) all.equal(A4[ch.A4@perm + 1L, ch.A4@perm + 1L], as(crossprod(R4 ), "symmetricMatrix")) all.equal(diag(R4.nopivot), sqrt(diag(ch.A4.nopivot))) all.equal(diag(R4), sqrt(diag(ch.A4))) all.equal(sqrt(det4), det(R4.nopivot)) all.equal(sqrt(det4), det(R4)) all.equal(det4, det(ch.A4.nopivot, sqrt = FALSE)) all.equal(det4, det(ch.A4, sqrt = FALSE)) all.equal(x4, solve(R4.nopivot, solve(t(R4.nopivot), b4))) all.equal(x4, solve(ch.A4.nopivot, b4)) all.equal(x4, solve(ch.A4, b4)) })
Given formally upper and lower triangular matrices
and , compute
and , respectively.
This function can be seen as way to compute the inverse of a
symmetric positive definite matrix given its Cholesky factor.
Equivalently, it can be seen as a way to compute
given the part of the
QR factorization of , if is constrained to have
positive diagonal entries.
chol2inv(x, ...) ## S4 method for signature 'denseMatrix' chol2inv(x, uplo = "U", ...) ## S4 method for signature 'sparseMatrix' chol2inv(x, uplo = "U", ...)chol2inv(x, ...) ## S4 method for signature 'denseMatrix' chol2inv(x, uplo = "U", ...) ## S4 method for signature 'sparseMatrix' chol2inv(x, uplo = "U", ...)
x |
a square matrix or |
uplo |
a string, either |
... |
further arguments passed to or from methods. |
A matrix, symmetricMatrix,
or diagonalMatrix representing
the inverse of the positive definite matrix whose
Cholesky factor is x.
The result is a traditional matrix if x is a
traditional matrix, dense if x is dense, and
sparse if x is sparse.
The default method from base, chol2inv,
called for traditional matrices x.
Generic function chol, for computing the upper
triangular Cholesky factor of a symmetric positive
semidefinite matrix.
Generic function solve, for solving linear systems
and (as a corollary) for computing inverses more generally.
(A <- Matrix(cbind(c(1, 1, 1), c(1, 2, 4), c(1, 4, 16)))) (R <- chol(A)) (L <- t(R)) (R2i <- chol2inv(R)) (L2i <- chol2inv(R)) stopifnot(exprs = { all.equal(R2i, tcrossprod(solve(R))) all.equal(L2i, crossprod(solve(L))) all.equal(as(R2i %*% A, "matrix"), diag(3L)) # the identity all.equal(as(L2i %*% A, "matrix"), diag(3L)) # ditto })(A <- Matrix(cbind(c(1, 1, 1), c(1, 2, 4), c(1, 4, 16)))) (R <- chol(A)) (L <- t(R)) (R2i <- chol2inv(R)) (L2i <- chol2inv(R)) stopifnot(exprs = { all.equal(R2i, tcrossprod(solve(R))) all.equal(L2i, crossprod(solve(L))) all.equal(as(R2i %*% A, "matrix"), diag(3L)) # the identity all.equal(as(L2i %*% A, "matrix"), diag(3L)) # ditto })
Computes the pivoted Cholesky factorization of an
real, symmetric matrix ,
which has the general form
or (equivalently)
where
is a permutation matrix,
is a unit lower triangular matrix,
is a diagonal matrix, and
.
The second equalities hold only for positive semidefinite ,
for which the diagonal entries of are non-negative
and is well-defined.
Methods for denseMatrix are built on
LAPACK routines dpstrf, dpotrf, and dpptrf.
The latter two do not permute rows or columns,
so that is an identity matrix.
Methods for sparseMatrix are built on
CHOLMOD routines cholmod_analyze and cholmod_factorize_p.
Cholesky(A, ...) ## S4 method for signature 'denseMatrix' Cholesky(A, perm = TRUE, tol = -1, uplo = "U", ...) ## S4 method for signature 'CsparseMatrix' Cholesky(A, perm = TRUE, LDL = !super, super = FALSE, Imult = 0, force = TRUE, uplo = "U", ...) ## S4 method for signature 'matrix' Cholesky(A, ...)Cholesky(A, ...) ## S4 method for signature 'denseMatrix' Cholesky(A, perm = TRUE, tol = -1, uplo = "U", ...) ## S4 method for signature 'CsparseMatrix' Cholesky(A, perm = TRUE, LDL = !super, super = FALSE, Imult = 0, force = TRUE, uplo = "U", ...) ## S4 method for signature 'matrix' Cholesky(A, ...)
A |
a finite, symmetric matrix or
|
perm |
a logical indicating if the rows and columns
of |
tol |
a finite numeric tolerance,
used only if |
LDL |
a logical indicating if the simplicial factorization
should be computed as
|
super |
a logical indicating if the factorization should
use the supernodal algorithm. The alternative is the simplicial
algorithm. Setting |
Imult |
a finite number. The matrix
that is factorized is |
force |
. |
uplo |
a string, either |
... |
further arguments passed to or from methods. |
Note that the result of a call to Cholesky inherits
from CholeskyFactorization but not
Matrix. Users who just want a matrix
should consider using chol, whose methods are
simple wrappers around Cholesky returning just the
upper triangular Cholesky factor ,
typically as a triangularMatrix.
However, a more principled approach would be to construct
factors as needed from the CholeskyFactorization object,
e.g., with expand1(x, "L"), if x is the
object.
The behaviour of Cholesky(A, perm = TRUE) for dense A
is somewhat exceptional, in that it expects without checking
that A is positive semidefinite. By construction, if
is positive semidefinite and the exact algorithm encounters a zero
pivot, then the unfactorized trailing submatrix is the zero matrix,
and there is nothing left to do. Hence when the finite precision
algorithm encounters a pivot less than tol, it signals a
warning instead of an error and zeros the trailing submatrix in
order to guarantee that is positive
semidefinite even if is not. It follows that one way to
test for positive semidefiniteness of in the event of a
warning is to analyze the error
See the examples and LAPACK Working Note (“LAWN”) 161 for details.
An object representing the factorization, inheriting from
virtual class CholeskyFactorization.
For a traditional matrix A, the specific class is
Cholesky.
For A inheriting from
unpackedMatrix,
packedMatrix, and
sparseMatrix,
the specific class is
Cholesky,
pCholesky, and
dCHMsimpl or dCHMsuper,
respectively.
The LAPACK source code, including documentation; see https://netlib.org/lapack/double/dpstrf.f, https://netlib.org/lapack/double/dpotrf.f, and https://netlib.org/lapack/double/dpptrf.f.
The CHOLMOD source code; see
https://github.com/DrTimothyAldenDavis/SuiteSparse,
notably the header file ‘CHOLMOD/Include/cholmod.h’
defining cholmod_factor_struct.
Lucas, C. (2004). LAPACK-style codes for level 2 and 3 pivoted Cholesky factorizations. LAPACK Working Note, Number 161. https://www.netlib.org/lapack/lawnspdf/lawn161.pdf
Chen, Y., Davis, T. A., Hager, W. W., & Rajamanickam, S. (2008). Algorithm 887: CHOLMOD, supernodal sparse Cholesky factorization and update/downdate. ACM Transactions on Mathematical Software, 35(3), Article 22, 1-14. doi:10.1145/1391989.1391995
Amestoy, P. R., Davis, T. A., & Duff, I. S. (2004). Algorithm 837: AMD, an approximate minimum degree ordering algorithm. ACM Transactions on Mathematical Software, 17(4), 886-905. doi:10.1145/1024074.1024081
Golub, G. H., & Van Loan, C. F. (2013). Matrix computations (4th ed.). Johns Hopkins University Press. doi:10.56021/9781421407944
Classes Cholesky, pCholesky,
dCHMsimpl and dCHMsuper
and their methods.
Classes dpoMatrix, dppMatrix,
and dsCMatrix.
Generic function chol,
for obtaining the upper triangular Cholesky factor as a
matrix or Matrix.
Generic functions expand1 and expand2,
for constructing matrix factors from the result.
Generic functions BunchKaufman, Schur,
lu, and qr,
for computing other factorizations.
showMethods("Cholesky", inherited = FALSE) set.seed(0) ## ---- Dense ---------------------------------------------------------- ## .... Positive definite .............................................. n <- 6L (A1 <- crossprod(Matrix(rnorm(n * n), n, n))) (ch.A1.nopivot <- Cholesky(A1, perm = FALSE)) (ch.A1 <- Cholesky(A1)) stopifnot(exprs = { length(ch.A1@perm) == ncol(A1) isPerm(ch.A1@perm) is.unsorted(ch.A1@perm) # typically not the identity permutation length(ch.A1.nopivot@perm) == 0L }) ## A ~ P1' L D L' P1 ~ P1' L L' P1 in floating point str(e.ch.A1 <- expand2(ch.A1, LDL = TRUE), max.level = 2L) str(E.ch.A1 <- expand2(ch.A1, LDL = FALSE), max.level = 2L) stopifnot(exprs = { all.equal(as(A1, "matrix"), as(Reduce(`%*%`, e.ch.A1), "matrix")) all.equal(as(A1, "matrix"), as(Reduce(`%*%`, E.ch.A1), "matrix")) }) ## .... Positive semidefinite but not positive definite ................ A2 <- A1 A2[1L, ] <- A2[, 1L] <- 0 A2 try(Cholesky(A2, perm = FALSE)) # fails as not positive definite ch.A2 <- Cholesky(A2) # returns, with a warning and ... A2.hat <- Reduce(`%*%`, expand2(ch.A2, LDL = FALSE)) norm(A2 - A2.hat, "2") / norm(A2, "2") # 7.670858e-17 ## .... Not positive semidefinite ...................................... A3 <- A1 A3[1L, ] <- A3[, 1L] <- -1 A3 try(Cholesky(A3, perm = FALSE)) # fails as not positive definite ch.A3 <- Cholesky(A3) # returns, with a warning and ... A3.hat <- Reduce(`%*%`, expand2(ch.A3, LDL = FALSE)) norm(A3 - A3.hat, "2") / norm(A3, "2") # 1.781568 ## Indeed, 'A3' is not positive semidefinite, but 'A3.hat' _is_ ch.A3.hat <- Cholesky(A3.hat) A3.hat.hat <- Reduce(`%*%`, expand2(ch.A3.hat, LDL = FALSE)) norm(A3.hat - A3.hat.hat, "2") / norm(A3.hat, "2") # 1.777944e-16 ## ---- Sparse --------------------------------------------------------- ## Really just three cases modulo permutation : ## ## type factorization minors of P1 A P1' ## 1 simplicial P1 A P1' = L1 D L1' nonzero ## 2 simplicial P1 A P1' = L L ' positive ## 3 supernodal P1 A P2' = L L ' positive data(KNex, package = "Matrix") A4 <- crossprod(KNex[["mm"]]) ch.A4 <- list(pivoted = list(simpl1 = Cholesky(A4, perm = TRUE, super = FALSE, LDL = TRUE), simpl0 = Cholesky(A4, perm = TRUE, super = FALSE, LDL = FALSE), super0 = Cholesky(A4, perm = TRUE, super = TRUE )), unpivoted = list(simpl1 = Cholesky(A4, perm = FALSE, super = FALSE, LDL = TRUE), simpl0 = Cholesky(A4, perm = FALSE, super = FALSE, LDL = FALSE), super0 = Cholesky(A4, perm = FALSE, super = TRUE ))) ch.A4 s <- simplify2array rapply2 <- function(object, f, ...) rapply(object, f, , , how = "list", ...) s(rapply2(ch.A4, isLDL)) s(m.ch.A4 <- rapply2(ch.A4, expand1, "L")) # giving L = L1 sqrt(D) ## By design, the pivoted and simplicial factorizations ## are more sparse than the unpivoted and supernodal ones ... s(rapply2(m.ch.A4, object.size)) ## Which is nicely visualized by lattice-based methods for 'image' inm <- c("pivoted", "unpivoted") jnm <- c("simpl1", "simpl0", "super0") for(i in 1:2) for(j in 1:3) print(image(m.ch.A4[[c(i, j)]], main = paste(inm[i], jnm[j])), split = c(j, i, 3L, 2L), more = i * j < 6L) simpl1 <- ch.A4[[c("pivoted", "simpl1")]] stopifnot(exprs = { length(simpl1@perm) == ncol(A4) isPerm(simpl1@perm, 0L) is.unsorted(simpl1@perm) # typically not the identity permutation }) ## One can expand with and without D regardless of isLDL(.), ## but "without" requires L = L1 sqrt(D), which is conditional ## on min(diag(D)) >= 0, hence "with" is the default isLDL(simpl1) stopifnot(min(diag(simpl1)) >= 0) str(e.ch.A4 <- expand2(simpl1, LDL = TRUE), max.level = 2L) # default str(E.ch.A4 <- expand2(simpl1, LDL = FALSE), max.level = 2L) stopifnot(exprs = { all.equal(E.ch.A4[["L" ]], e.ch.A4[["L1" ]] %*% sqrt(e.ch.A4[["D"]])) all.equal(E.ch.A4[["L."]], sqrt(e.ch.A4[["D"]]) %*% e.ch.A4[["L1."]]) all.equal(A4, as(Reduce(`%*%`, e.ch.A4), "posdefMatrix")) all.equal(A4, as(Reduce(`%*%`, E.ch.A4), "posdefMatrix")) }) ## The "same" permutation matrix with "alternate" representation ## [i, perm[i]] {margin=1} <-> [invertPerm(perm)[j], j] {margin=2} alt <- function(P) { P@margin <- 1L + !(P@margin - 1L) # 1 <-> 2 P@perm <- invertPerm(P@perm) P } ## Expansions are elegant but inefficient (transposes are redundant) ## hence programmers should consider methods for 'expand1' and 'diag' stopifnot(exprs = { identical(expand1(simpl1, "P1"), alt(e.ch.A4[["P1"]])) identical(expand1(simpl1, "L"), E.ch.A4[["L"]]) identical(Diagonal(x = diag(simpl1)), e.ch.A4[["D"]]) }) ## chol(A, pivot = value) is a simple wrapper around ## Cholesky(A, perm = value, LDL = FALSE, super = FALSE), ## returning L' = sqrt(D) L1' _but_ giving no information ## about the permutation P1 selectMethod("chol", "dsCMatrix") stopifnot(all.equal(chol(A4, pivot = TRUE), E.ch.A4[["L."]])) ## Now a symmetric matrix with positive _and_ negative eigenvalues, ## hence _not_ positive semidefinite A5 <- new("dsCMatrix", Dim = c(7L, 7L), p = c(0:1, 3L, 6:7, 10:11, 15L), i = c(0L, 0:1, 0:3, 2:5, 3:6), x = c(1, 6, 38, 10, 60, 103, -4, 6, -32, -247, -2, -16, -128, -2, -67)) (ev <- eigen(A5, only.values = TRUE)$values) (t.ev <- table(factor(sign(ev), -1:1))) # the matrix "inertia" ch.A5 <- Cholesky(A5) isLDL(ch.A5) (d.A5 <- diag(ch.A5)) # diag(D) is partly negative ## Sylvester's law of inertia holds here, but not in general ## in finite precision arithmetic stopifnot(identical(table(factor(sign(d.A5), -1:1)), t.ev)) try(expand1(ch.A5, "L")) # unable to compute L = L1 sqrt(D) try(expand2(ch.A5, LDL = FALSE)) # ditto try(chol(A5, pivot = TRUE)) # ditto ## The default expansion is "square root free" and still works here str(e.ch.A5 <- expand2(ch.A5, LDL = TRUE), max.level = 2L) stopifnot(all.equal(A5, as(Reduce(`%*%`, e.ch.A5), "symmetricMatrix"))) ## Version of the SuiteSparse library, which includes CHOLMOD Mv <- Matrix.Version() Mv[["suitesparse"]]showMethods("Cholesky", inherited = FALSE) set.seed(0) ## ---- Dense ---------------------------------------------------------- ## .... Positive definite .............................................. n <- 6L (A1 <- crossprod(Matrix(rnorm(n * n), n, n))) (ch.A1.nopivot <- Cholesky(A1, perm = FALSE)) (ch.A1 <- Cholesky(A1)) stopifnot(exprs = { length(ch.A1@perm) == ncol(A1) isPerm(ch.A1@perm) is.unsorted(ch.A1@perm) # typically not the identity permutation length(ch.A1.nopivot@perm) == 0L }) ## A ~ P1' L D L' P1 ~ P1' L L' P1 in floating point str(e.ch.A1 <- expand2(ch.A1, LDL = TRUE), max.level = 2L) str(E.ch.A1 <- expand2(ch.A1, LDL = FALSE), max.level = 2L) stopifnot(exprs = { all.equal(as(A1, "matrix"), as(Reduce(`%*%`, e.ch.A1), "matrix")) all.equal(as(A1, "matrix"), as(Reduce(`%*%`, E.ch.A1), "matrix")) }) ## .... Positive semidefinite but not positive definite ................ A2 <- A1 A2[1L, ] <- A2[, 1L] <- 0 A2 try(Cholesky(A2, perm = FALSE)) # fails as not positive definite ch.A2 <- Cholesky(A2) # returns, with a warning and ... A2.hat <- Reduce(`%*%`, expand2(ch.A2, LDL = FALSE)) norm(A2 - A2.hat, "2") / norm(A2, "2") # 7.670858e-17 ## .... Not positive semidefinite ...................................... A3 <- A1 A3[1L, ] <- A3[, 1L] <- -1 A3 try(Cholesky(A3, perm = FALSE)) # fails as not positive definite ch.A3 <- Cholesky(A3) # returns, with a warning and ... A3.hat <- Reduce(`%*%`, expand2(ch.A3, LDL = FALSE)) norm(A3 - A3.hat, "2") / norm(A3, "2") # 1.781568 ## Indeed, 'A3' is not positive semidefinite, but 'A3.hat' _is_ ch.A3.hat <- Cholesky(A3.hat) A3.hat.hat <- Reduce(`%*%`, expand2(ch.A3.hat, LDL = FALSE)) norm(A3.hat - A3.hat.hat, "2") / norm(A3.hat, "2") # 1.777944e-16 ## ---- Sparse --------------------------------------------------------- ## Really just three cases modulo permutation : ## ## type factorization minors of P1 A P1' ## 1 simplicial P1 A P1' = L1 D L1' nonzero ## 2 simplicial P1 A P1' = L L ' positive ## 3 supernodal P1 A P2' = L L ' positive data(KNex, package = "Matrix") A4 <- crossprod(KNex[["mm"]]) ch.A4 <- list(pivoted = list(simpl1 = Cholesky(A4, perm = TRUE, super = FALSE, LDL = TRUE), simpl0 = Cholesky(A4, perm = TRUE, super = FALSE, LDL = FALSE), super0 = Cholesky(A4, perm = TRUE, super = TRUE )), unpivoted = list(simpl1 = Cholesky(A4, perm = FALSE, super = FALSE, LDL = TRUE), simpl0 = Cholesky(A4, perm = FALSE, super = FALSE, LDL = FALSE), super0 = Cholesky(A4, perm = FALSE, super = TRUE ))) ch.A4 s <- simplify2array rapply2 <- function(object, f, ...) rapply(object, f, , , how = "list", ...) s(rapply2(ch.A4, isLDL)) s(m.ch.A4 <- rapply2(ch.A4, expand1, "L")) # giving L = L1 sqrt(D) ## By design, the pivoted and simplicial factorizations ## are more sparse than the unpivoted and supernodal ones ... s(rapply2(m.ch.A4, object.size)) ## Which is nicely visualized by lattice-based methods for 'image' inm <- c("pivoted", "unpivoted") jnm <- c("simpl1", "simpl0", "super0") for(i in 1:2) for(j in 1:3) print(image(m.ch.A4[[c(i, j)]], main = paste(inm[i], jnm[j])), split = c(j, i, 3L, 2L), more = i * j < 6L) simpl1 <- ch.A4[[c("pivoted", "simpl1")]] stopifnot(exprs = { length(simpl1@perm) == ncol(A4) isPerm(simpl1@perm, 0L) is.unsorted(simpl1@perm) # typically not the identity permutation }) ## One can expand with and without D regardless of isLDL(.), ## but "without" requires L = L1 sqrt(D), which is conditional ## on min(diag(D)) >= 0, hence "with" is the default isLDL(simpl1) stopifnot(min(diag(simpl1)) >= 0) str(e.ch.A4 <- expand2(simpl1, LDL = TRUE), max.level = 2L) # default str(E.ch.A4 <- expand2(simpl1, LDL = FALSE), max.level = 2L) stopifnot(exprs = { all.equal(E.ch.A4[["L" ]], e.ch.A4[["L1" ]] %*% sqrt(e.ch.A4[["D"]])) all.equal(E.ch.A4[["L."]], sqrt(e.ch.A4[["D"]]) %*% e.ch.A4[["L1."]]) all.equal(A4, as(Reduce(`%*%`, e.ch.A4), "posdefMatrix")) all.equal(A4, as(Reduce(`%*%`, E.ch.A4), "posdefMatrix")) }) ## The "same" permutation matrix with "alternate" representation ## [i, perm[i]] {margin=1} <-> [invertPerm(perm)[j], j] {margin=2} alt <- function(P) { P@margin <- 1L + !(P@margin - 1L) # 1 <-> 2 P@perm <- invertPerm(P@perm) P } ## Expansions are elegant but inefficient (transposes are redundant) ## hence programmers should consider methods for 'expand1' and 'diag' stopifnot(exprs = { identical(expand1(simpl1, "P1"), alt(e.ch.A4[["P1"]])) identical(expand1(simpl1, "L"), E.ch.A4[["L"]]) identical(Diagonal(x = diag(simpl1)), e.ch.A4[["D"]]) }) ## chol(A, pivot = value) is a simple wrapper around ## Cholesky(A, perm = value, LDL = FALSE, super = FALSE), ## returning L' = sqrt(D) L1' _but_ giving no information ## about the permutation P1 selectMethod("chol", "dsCMatrix") stopifnot(all.equal(chol(A4, pivot = TRUE), E.ch.A4[["L."]])) ## Now a symmetric matrix with positive _and_ negative eigenvalues, ## hence _not_ positive semidefinite A5 <- new("dsCMatrix", Dim = c(7L, 7L), p = c(0:1, 3L, 6:7, 10:11, 15L), i = c(0L, 0:1, 0:3, 2:5, 3:6), x = c(1, 6, 38, 10, 60, 103, -4, 6, -32, -247, -2, -16, -128, -2, -67)) (ev <- eigen(A5, only.values = TRUE)$values) (t.ev <- table(factor(sign(ev), -1:1))) # the matrix "inertia" ch.A5 <- Cholesky(A5) isLDL(ch.A5) (d.A5 <- diag(ch.A5)) # diag(D) is partly negative ## Sylvester's law of inertia holds here, but not in general ## in finite precision arithmetic stopifnot(identical(table(factor(sign(d.A5), -1:1)), t.ev)) try(expand1(ch.A5, "L")) # unable to compute L = L1 sqrt(D) try(expand2(ch.A5, LDL = FALSE)) # ditto try(chol(A5, pivot = TRUE)) # ditto ## The default expansion is "square root free" and still works here str(e.ch.A5 <- expand2(ch.A5, LDL = TRUE), max.level = 2L) stopifnot(all.equal(A5, as(Reduce(`%*%`, e.ch.A5), "symmetricMatrix"))) ## Version of the SuiteSparse library, which includes CHOLMOD Mv <- Matrix.Version() Mv[["suitesparse"]]
Since 2005, package Matrix has supported coercions to and
from class graph from package
graph.
Since 2013, this functionality has been exposed via functions
T2graph and graph2T, which, unlike methods for
as(from, "<Class>"), support optional arguments.
graph2T(from, use.weights = ) T2graph(from, need.uniq = !isUniqueT(from), edgemode = NULL)graph2T(from, use.weights = ) T2graph(from, need.uniq = !isUniqueT(from), edgemode = NULL)
from |
for |
use.weights |
logical indicating if weights should be used, i.e.,
equivalently the result will be numeric, i.e. of class
|
need.uniq |
a logical indicating if |
edgemode |
one of |
For graph2T(), a sparse matrix inheriting from
"TsparseMatrix".
For T2graph() an R object of class "graph".
Package igraph, which provides similar coercions
to and from its class igraph via functions
graph_from_adjacency_matrix and as_adjacency_matrix.
if(requireNamespace("graph")) { n4 <- LETTERS[1:4]; dns <- list(n4,n4) show(a1 <- sparseMatrix(i= c(1:4), j=c(2:4,1), x = 2, dimnames=dns)) show(g1 <- as(a1, "graph")) # directed unlist(graph::edgeWeights(g1)) # all '2' show(a2 <- sparseMatrix(i= c(1:4,4), j=c(2:4,1:2), x = TRUE, dimnames=dns)) show(g2 <- as(a2, "graph")) # directed # now if you want it undirected: show(g3 <- T2graph(as(a2,"TsparseMatrix"), edgemode="undirected")) show(m3 <- as(g3,"Matrix")) show( graph2T(g3) ) # a "pattern Matrix" (nsTMatrix) a. <- sparseMatrix(i=4:1, j=1:4, dimnames=list(n4, n4), repr="T") # no 'x' show(a.) # "ngTMatrix" show(g. <- as(a., "graph")) }if(requireNamespace("graph")) { n4 <- LETTERS[1:4]; dns <- list(n4,n4) show(a1 <- sparseMatrix(i= c(1:4), j=c(2:4,1), x = 2, dimnames=dns)) show(g1 <- as(a1, "graph")) # directed unlist(graph::edgeWeights(g1)) # all '2' show(a2 <- sparseMatrix(i= c(1:4,4), j=c(2:4,1:2), x = TRUE, dimnames=dns)) show(g2 <- as(a2, "graph")) # directed # now if you want it undirected: show(g3 <- T2graph(as(a2,"TsparseMatrix"), edgemode="undirected")) show(m3 <- as(g3,"Matrix")) show( graph2T(g3) ) # a "pattern Matrix" (nsTMatrix) a. <- sparseMatrix(i=4:1, j=1:4, dimnames=list(n4, n4), repr="T") # no 'x' show(a.) # "ngTMatrix" show(g. <- as(a., "graph")) }
Methods for coercion from and to sparse matrices from package SparseM
are provided here, for ease of porting functionality to the
Matrix package, and comparing functionality of the two
packages. All these work via the usual as(., "<class>")
coercion,
as(from, Class)
...
...
...
...
...
...
...
...
...
...
...
...
The documentation in CRAN package SparseM, such as
SparseM.ontology, and one important class,
matrix.csr.
Form row and column sums and means for
objects, for sparseMatrix the result may
optionally be sparse (sparseVector), too.
Row or column names are kept respectively as for base matrices
and colSums methods, when the result is
numeric vector.
colSums(x, na.rm = FALSE, dims = 1L, ...) rowSums(x, na.rm = FALSE, dims = 1L, ...) colMeans(x, na.rm = FALSE, dims = 1L, ...) rowMeans(x, na.rm = FALSE, dims = 1L, ...) ## S4 method for signature 'CsparseMatrix' colSums(x, na.rm = FALSE, dims = 1L, sparseResult = FALSE, ...) ## S4 method for signature 'CsparseMatrix' rowSums(x, na.rm = FALSE, dims = 1L, sparseResult = FALSE, ...) ## S4 method for signature 'CsparseMatrix' colMeans(x, na.rm = FALSE, dims = 1L, sparseResult = FALSE, ...) ## S4 method for signature 'CsparseMatrix' rowMeans(x, na.rm = FALSE, dims = 1L, sparseResult = FALSE, ...)colSums(x, na.rm = FALSE, dims = 1L, ...) rowSums(x, na.rm = FALSE, dims = 1L, ...) colMeans(x, na.rm = FALSE, dims = 1L, ...) rowMeans(x, na.rm = FALSE, dims = 1L, ...) ## S4 method for signature 'CsparseMatrix' colSums(x, na.rm = FALSE, dims = 1L, sparseResult = FALSE, ...) ## S4 method for signature 'CsparseMatrix' rowSums(x, na.rm = FALSE, dims = 1L, sparseResult = FALSE, ...) ## S4 method for signature 'CsparseMatrix' colMeans(x, na.rm = FALSE, dims = 1L, sparseResult = FALSE, ...) ## S4 method for signature 'CsparseMatrix' rowMeans(x, na.rm = FALSE, dims = 1L, sparseResult = FALSE, ...)
x |
a Matrix, i.e., inheriting from |
na.rm |
logical. Should missing values (including |
dims |
completely ignored by the |
... |
potentially further arguments, for method |
sparseResult |
logical indicating if the result should be sparse,
i.e., inheriting from class |
returns a numeric vector if sparseResult is FALSE as per
default. Otherwise, returns a sparseVector.
dimnames(x) are only kept (as names(v))
when the resulting v is numeric, since
sparseVectors do not have names.
colSums and the
sparseVector classes.
(M <- bdiag(Diagonal(2), matrix(1:3, 3,4), diag(3:2))) # 7 x 8 colSums(M) d <- Diagonal(10, c(0,0,10,0,2,rep(0,5))) MM <- kronecker(d, M) dim(MM) # 70 80 length(MM@x) # 160, but many are '0' ; drop those: MM <- drop0(MM) length(MM@x) # 32 cm <- colSums(MM) (scm <- colSums(MM, sparseResult = TRUE)) stopifnot(is(scm, "sparseVector"), identical(cm, as.numeric(scm))) rowSums (MM, sparseResult = TRUE) # 14 of 70 are not zero colMeans(MM, sparseResult = TRUE) # 16 of 80 are not zero ## Since we have no 'NA's, these two are equivalent : stopifnot(identical(rowMeans(MM, sparseResult = TRUE), rowMeans(MM, sparseResult = TRUE, na.rm = TRUE)), rowMeans(Diagonal(16)) == 1/16, colSums(Diagonal(7)) == 1) ## dimnames(x) --> names( <value> ) : dimnames(M) <- list(paste0("r", 1:7), paste0("V",1:8)) M colSums(M) rowMeans(M) ## Assertions : stopifnot(exprs = { all.equal(colSums(M), structure(c(1,1,6,6,6,6,3,2), names = colnames(M))) all.equal(rowMeans(M), structure(c(1,1,4,8,12,3,2)/8, names = paste0("r", 1:7))) })(M <- bdiag(Diagonal(2), matrix(1:3, 3,4), diag(3:2))) # 7 x 8 colSums(M) d <- Diagonal(10, c(0,0,10,0,2,rep(0,5))) MM <- kronecker(d, M) dim(MM) # 70 80 length(MM@x) # 160, but many are '0' ; drop those: MM <- drop0(MM) length(MM@x) # 32 cm <- colSums(MM) (scm <- colSums(MM, sparseResult = TRUE)) stopifnot(is(scm, "sparseVector"), identical(cm, as.numeric(scm))) rowSums (MM, sparseResult = TRUE) # 14 of 70 are not zero colMeans(MM, sparseResult = TRUE) # 16 of 80 are not zero ## Since we have no 'NA's, these two are equivalent : stopifnot(identical(rowMeans(MM, sparseResult = TRUE), rowMeans(MM, sparseResult = TRUE, na.rm = TRUE)), rowMeans(Diagonal(16)) == 1/16, colSums(Diagonal(7)) == 1) ## dimnames(x) --> names( <value> ) : dimnames(M) <- list(paste0("r", 1:7), paste0("V",1:8)) M colSums(M) rowMeans(M) ## Assertions : stopifnot(exprs = { all.equal(colSums(M), structure(c(1,1,6,6,6,6,3,2), names = colnames(M))) all.equal(rowMeans(M), structure(c(1,1,4,8,12,3,2)/8, names = paste0("r", 1:7))) })
“Estimate”, i.e. compute approximately the CONDition number of
a (potentially large, often sparse) matrix A.
It works by apply a fast randomized approximation of the 1-norm,
norm(A,"1"), through onenormest(.).
condest(A, t = min(n, 5), normA = norm(A, "1"), silent = FALSE, quiet = TRUE) onenormest(A, t = min(n, 5), A.x, At.x, n, silent = FALSE, quiet = silent, iter.max = 10, eps = 4 * .Machine$double.eps)condest(A, t = min(n, 5), normA = norm(A, "1"), silent = FALSE, quiet = TRUE) onenormest(A, t = min(n, 5), A.x, At.x, n, silent = FALSE, quiet = silent, iter.max = 10, eps = 4 * .Machine$double.eps)
A |
a square matrix, optional for |
t |
number of columns to use in the iterations. |
normA |
number; (an estimate of) the 1-norm of |
silent |
logical indicating if warning and (by default) convergence messages should be displayed. |
quiet |
logical indicating if convergence messages should be displayed. |
A.x, At.x
|
when |
n |
|
iter.max |
maximal number of iterations for the 1-norm estimator. |
eps |
the relative change that is deemed irrelevant. |
condest() calls lu(A), and subsequently
onenormest(A.x = , At.x = ) to compute an approximate norm of
the inverse of A, , in a way which
keeps using sparse matrices efficiently when A is sparse.
Note that onenormest() uses random vectors and hence
both functions' results are random, i.e., depend on the random
seed, see, e.g., set.seed().
Both functions return a list;
condest() with components,
est |
a number |
v |
the maximal |
The function onenormest() returns a list with components,
est |
a number |
v |
0-1 integer vector length |
w |
numeric vector, the largest |
iter |
the number of iterations used. |
This is based on octave's condest() and
onenormest() implementations with original author
Jason Riedy, U Berkeley; translation to R and
adaption by Martin Maechler.
Nicholas J. Higham and Françoise Tisseur (2000). A Block Algorithm for Matrix 1-Norm Estimation, with an Application to 1-Norm Pseudospectra. SIAM J. Matrix Anal. Appl. 21, 4, 1185–1201.
William W. Hager (1984). Condition Estimates. SIAM J. Sci. Stat. Comput. 5, 311–316.
data(KNex, package = "Matrix") mtm <- with(KNex, crossprod(mm)) system.time(ce <- condest(mtm)) sum(abs(ce$v)) ## || v ||_1 == 1 ## Prove that || A v || = || A || / est (as ||v|| = 1): stopifnot(all.equal(norm(mtm %*% ce$v), norm(mtm) / ce$est)) ## reciprocal 1 / ce$est system.time(rc <- rcond(mtm)) # takes ca 3 x longer rc all.equal(rc, 1/ce$est) # TRUE -- the approximation was good one <- onenormest(mtm) str(one) ## est = 12.3 ## the maximal column: which(one$v == 1) # mostly 4, rarely 1, depending on random seeddata(KNex, package = "Matrix") mtm <- with(KNex, crossprod(mm)) system.time(ce <- condest(mtm)) sum(abs(ce$v)) ## || v ||_1 == 1 ## Prove that || A v || = || A || / est (as ||v|| = 1): stopifnot(all.equal(norm(mtm %*% ce$v), norm(mtm) / ce$est)) ## reciprocal 1 / ce$est system.time(rc <- rcond(mtm)) # takes ca 3 x longer rc all.equal(rc, 1/ce$est) # TRUE -- the approximation was good one <- onenormest(mtm) str(one) ## est = 12.3 ## the maximal column: which(one$v == 1) # mostly 4, rarely 1, depending on random seed
CsparseMatrix is a virtual subclass of
sparseMatrix representing compressed sparse
column (CSC) format matrices. To represent an m-by-n
matrix A, this format stores the positions of m*n or
fewer (often ) entries of A,
ordering these by column then by row. Authors of subclasses of
CsparseMatrix are free to declare how this information is used
to specify A. See ‘Subclasses’ for subclasses defined
in package Matrix.
Dim, Dimnames
inherited from virtual superclass
Matrix.
pan integer vector of length Dim[2]+1
corresponding to a subset V of the set of entries of
A. p[j+1] is the number of elements of V
belonging to one of the first j columns of A,
implying
0 = p[1] <= p[j] <= p[j+1] <= p[length(p)] = |V|
where |V| denotes the size of V. The number of
elements of V belonging to column j of A is
given by p[j+1]-p[j] or, equivalently, diff(p)[j].
ian integer vector of length p[length(p)]
storing the 0-based row indices of the elements of V
ordered by column then by row. Hence, to be valid, i must
satisfy 0 <= i < Dim[1] and be increasing within the
contiguous segments that partition it by column of A.
The segment corresponding to column j can be accessed as
i[(p[j]+1):p[j+1]] if p[j] < p[j+1] and by
i[seq.int(from=p[j], length.out=p[j+1]-p[j])] more
generally. Experimentally, length(i) is allowed to exceed
p[length(p)]; if it does, then the excess elements of
i are unreferenced.
The nonvirtual subclasses of CsparseMatrix defined in package
Matrix are listed below with links to virtual superclasses
defining their data type and structure.
| Nonvirtual subclass | Data type | Structure |
ngCMatrix |
nMatrix |
generalMatrix
|
lgCMatrix |
lMatrix |
generalMatrix
|
igCMatrix |
iMatrix |
generalMatrix
|
dgCMatrix |
dMatrix |
generalMatrix
|
zgCMatrix |
zMatrix |
generalMatrix
|
nsCMatrix |
nMatrix |
symmetricMatrix
|
lsCMatrix |
lMatrix |
symmetricMatrix
|
isCMatrix |
iMatrix |
symmetricMatrix
|
dsCMatrix |
dMatrix |
symmetricMatrix
|
zsCMatrix |
zMatrix |
symmetricMatrix
|
dpCMatrix |
dMatrix |
posdefMatrix
|
zpCMatrix |
zMatrix |
posdefMatrix
|
ntCMatrix |
nMatrix |
triangularMatrix
|
ltCMatrix |
lMatrix |
triangularMatrix
|
itCMatrix |
iMatrix |
triangularMatrix
|
dtCMatrix |
dMatrix |
triangularMatrix
|
ztCMatrix |
zMatrix |
triangularMatrix
|
The subclasses of iMatrix, zMatrix, and
posdefMatrix were not defined until Matrix version 1.8-0.
Classes .gCMatrix represent general (unstructured, possibly
nonsquare) A. Objects have p and i slots
specifying a subset V of the set of entries of A, as
described in ‘Slots’. For ngCMatrix, whose data type is
boolean, the entries in V have value 1, and the entries not in
V have value 0. For other .gCMatrix, the entries in
V have values taken from an additional x slot (a
logical, integer, double, or complex vector), and the entries not in
V have value 0. The i and x slots are entirely
parallel, both using the ordering of V by column then by row.
Classes .sCMatrix represent Hermitian or symmetric A.
Compared to .gCMatrix, objects have an additional uplo
slot indicating a restriction on V. If uplo="U", then
V contains only upper triangular entries of A. If
uplo="L", then V contains only lower triangular entries
of A. The entries in V have value 1 (nsCMatrix)
or values taken from an x slot (other .sCMatrix). The
entries opposite the main diagonal, namely A[j, i] for all
A[i, j] in V, have value op(A[i, j]), where
op=Conj for Hermitian A and op=identity for
symmetric A. All other entries of A have value 0.
Objects of class zsCMatrix have an additional trans
slot that distinguishes Hermitian and symmetric A, which use
trans="C" and "T", respectively. If trans="C"
and V contains diagonal entries of A, then the imaginary
parts of the corresponding elements of x are not referenced.
(The diagonal entries of Hermitian matrices are real by definition.)
Classes dpCMatrix and zpCMatrix extend dsCMatrix
and zsCMatrix and represent positive semidefinite A.
Positive semidefiniteness of A induces a constraint on the
x slot. However, this constraint is not strictly enforced by
the validity methods, which test only that the diagonal entries of
A are nonnegative (a necessary, not sufficient condition).
For zpCMatrix, only trans="C" is valid.
Classes .tCMatrix represent triangular A. Compared to
.gCMatrix, objects have additional uplo and diag
slots indicating restrictions on V. If uplo="U", then
A is upper triangular and V contains only upper
triangular entries. If uplo="L", then A is lower
triangular and V contains only lower triangular entries. If
diag="U" (instead of "N"), then A is unit
triangular and V contains only strictly upper or lower
triangular entries. The entries in V have value 1
(ntCMatrix) or values taken from an x slot (other
.tCMatrix). With the exception of diagonal entries when
diag="U", which have value 1, entries not in V have
value 0.
“Sister” classes RsparseMatrix and
TsparseMatrix for compressed sparse row and
triplet format matrices. Generic functions
cbind2, colSums,
[ (when called as x[, j]), etc., whose
methods for CsparseMatrix are particularly efficient.
getClass("CsparseMatrix") ## The common validity check function (based on C code): getValidity(getClass("CsparseMatrix")) (m <- Matrix(c(0,0,2:0), 3,5)) str(m) m[,1] mm <- Matrix(toeplitz(c(10, 0, 1, 0, 3)), sparse = TRUE) mm # automatically dsCMatrix str(mm) mT <- as(as(mm, "generalMatrix"), "TsparseMatrix") ## Either (symM <- as(mT, "symmetricMatrix")) # dsT (symC <- as(symM, "CsparseMatrix")) # dsC ## or sT <- Matrix(mT, sparse=TRUE, forceCheck=TRUE) # dsT sym2 <- as(symC, "TsparseMatrix") ## --> the same as 'symM', a "dsTMatrix" showClass("dtCMatrix") showClass("dtTMatrix") t1 <- new("dtTMatrix", x= c(3,7), i= 0:1, j=3:2, Dim= as.integer(c(4,4))) t1 ## from 0-diagonal to unit-diagonal {low-level step}: tu <- t1 ; tu@diag <- "U" tu (cu <- as(tu, "CsparseMatrix")) str(cu)# only two entries in @i and @x stopifnot(cu@i == 1:0, all(2 * symmpart(cu) == Diagonal(4) + forceSymmetric(cu))) t1[1,2:3] <- -1:-2 diag(t1) <- 10*c(1:2,3:2) t1 # still triangular (it1 <- solve(t1)) t1. <- solve(it1) all(abs(t1 - t1.) < 10 * .Machine$double.eps) ## 2nd example U5 <- new("dtCMatrix", i= c(1L, 0:3), p=c(0L,0L,0:2, 5L), Dim = c(5L, 5L), x = rep(1, 5), diag = "U") U5 (iu <- solve(U5)) # contains one '0' validObject(iu2 <- solve(U5, Diagonal(5)))# failed in earlier versions I5 <- iu %*% U5 # should equal the identity matrix i5 <- iu2 %*% U5 m53 <- matrix(1:15, 5,3, dimnames=list(NULL,letters[1:3])) asDiag <- function(M) as(drop0(M), "diagonalMatrix") stopifnot( all.equal(Diagonal(5), asDiag(I5), tolerance=1e-14) , all.equal(Diagonal(5), asDiag(i5), tolerance=1e-14) , identical(list(NULL, dimnames(m53)[[2]]), dimnames(solve(U5, m53))) )getClass("CsparseMatrix") ## The common validity check function (based on C code): getValidity(getClass("CsparseMatrix")) (m <- Matrix(c(0,0,2:0), 3,5)) str(m) m[,1] mm <- Matrix(toeplitz(c(10, 0, 1, 0, 3)), sparse = TRUE) mm # automatically dsCMatrix str(mm) mT <- as(as(mm, "generalMatrix"), "TsparseMatrix") ## Either (symM <- as(mT, "symmetricMatrix")) # dsT (symC <- as(symM, "CsparseMatrix")) # dsC ## or sT <- Matrix(mT, sparse=TRUE, forceCheck=TRUE) # dsT sym2 <- as(symC, "TsparseMatrix") ## --> the same as 'symM', a "dsTMatrix" showClass("dtCMatrix") showClass("dtTMatrix") t1 <- new("dtTMatrix", x= c(3,7), i= 0:1, j=3:2, Dim= as.integer(c(4,4))) t1 ## from 0-diagonal to unit-diagonal {low-level step}: tu <- t1 ; tu@diag <- "U" tu (cu <- as(tu, "CsparseMatrix")) str(cu)# only two entries in @i and @x stopifnot(cu@i == 1:0, all(2 * symmpart(cu) == Diagonal(4) + forceSymmetric(cu))) t1[1,2:3] <- -1:-2 diag(t1) <- 10*c(1:2,3:2) t1 # still triangular (it1 <- solve(t1)) t1. <- solve(it1) all(abs(t1 - t1.) < 10 * .Machine$double.eps) ## 2nd example U5 <- new("dtCMatrix", i= c(1L, 0:3), p=c(0L,0L,0:2, 5L), Dim = c(5L, 5L), x = rep(1, 5), diag = "U") U5 (iu <- solve(U5)) # contains one '0' validObject(iu2 <- solve(U5, Diagonal(5)))# failed in earlier versions I5 <- iu %*% U5 # should equal the identity matrix i5 <- iu2 %*% U5 m53 <- matrix(1:15, 5,3, dimnames=list(NULL,letters[1:3])) asDiag <- function(M) as(drop0(M), "diagonalMatrix") stopifnot( all.equal(Diagonal(5), asDiag(I5), tolerance=1e-14) , all.equal(Diagonal(5), asDiag(i5), tolerance=1e-14) , identical(list(NULL, dimnames(m53)[[2]]), dimnames(solve(U5, m53))) )
Returns the conjugate transpose of a matrix or data frame, defined as
Conj(t(x)) if x has complex data and as
t(x) otherwise.
ct(x) ## S4 method for signature 'CsparseMatrix' ct(x) ## S4 method for signature 'RsparseMatrix' ct(x) ## S4 method for signature 'TsparseMatrix' ct(x) ## S4 method for signature 'denseMatrix' ct(x) ## S4 method for signature 'diagonalMatrix' ct(x) ## S4 method for signature 'indMatrix' ct(x) ## S4 method for signature 'pMatrix' ct(x) ## S4 method for signature 'sparseVector' ct(x) ## S4 method for signature 'vector' ct(x) .ctCRT(x, lazy = TRUE)ct(x) ## S4 method for signature 'CsparseMatrix' ct(x) ## S4 method for signature 'RsparseMatrix' ct(x) ## S4 method for signature 'TsparseMatrix' ct(x) ## S4 method for signature 'denseMatrix' ct(x) ## S4 method for signature 'diagonalMatrix' ct(x) ## S4 method for signature 'indMatrix' ct(x) ## S4 method for signature 'pMatrix' ct(x) ## S4 method for signature 'sparseVector' ct(x) ## S4 method for signature 'vector' ct(x) .ctCRT(x, lazy = TRUE)
x |
a R object representing a matrix or vector.
|
lazy |
a logical indicating if transposition can change the storage format. |
For consistency, methods for ct preserve the storage format of
matrix arguments, even if that is not most efficient. In particular,
if x is a CsparseMatrix object,
then ct(x) is a CsparseMatrix object, even though the
RsparseMatrix representation of the conjugate
transpose is obtained more cheaply. For “lazy” transposing of
compressed sparse column or row format matrices, interchanging the
column and row formats, use .ctCRT.
If x is formally Hermitian
(see symmetricMatrix),
then x and ct(x) represent the same matrix with opposite
uplo slots, such that one stores only the upper triangle and
the other stores only the lower triangle.
A Matrix object representing the conjugate
transpose of x. The class is a superclass of the class of
x unless x is a sparseVector
object.
t and .tCRT for matrix transpose
without conjugation. crossprod for matrix
products involving transposes.
ct(c(1+1i, 2-2i)) # as Conj(t(.)) for complex data typeof(x2 <- c(1L, 2L)) typeof(print( t(x2) )) # "integer" typeof(print( ct(x2) )) # "integer" typeof(print(Conj( t(x2)))) # "double" as 'Conj' coerces stopifnot(identical(ct(1:2), t(1:2)), # keeping non-complex data type identical(Conj(t(1:2)), 0 + t(1:2))) rcplx <- function (n) complex(modulus = rlnorm(n), argument = runif(n, 0, 2 * pi)) set.seed(14L) (X <- new("zgRMatrix", Dim = c(3L, 5L), Dimnames = list(A = paste0("a", 1:3), B = paste0("b", 1:5)), p = c(0L, 1L, 2L, 5L), j = c(1L, 0L, 0L, 1L, 4L), x = round(rcplx(5L), 2L))) ( ctX <- ct (X)) # compressed sparse row (.ctX <- .ctCRT(X)) # compressed sparse column stopifnot(identical(dim(ctX), dim(X)[2:1]), identical(dimnames(ctX), dimnames(X)[2:1]), identical(X, ct ( ctX)), identical(X, .ctCRT(.ctX)), identical( ctX, as(.ctX, "RsparseMatrix")), identical(.ctX, as( ctX, "CsparseMatrix")), identical(ctX, .ctCRT(X, lazy = FALSE))) (S <- crossprod(X, trans = "C")) # formally Hermitian (ctS <- ct(S)) # *output* is identical but stored triangle is different stopifnot(is(S, "zpRMatrix"), all.equal(S, ctS, tolerance = 0), S@uplo == "U", ctS@uplo == "L", identical(S, ct(ctS)))ct(c(1+1i, 2-2i)) # as Conj(t(.)) for complex data typeof(x2 <- c(1L, 2L)) typeof(print( t(x2) )) # "integer" typeof(print( ct(x2) )) # "integer" typeof(print(Conj( t(x2)))) # "double" as 'Conj' coerces stopifnot(identical(ct(1:2), t(1:2)), # keeping non-complex data type identical(Conj(t(1:2)), 0 + t(1:2))) rcplx <- function (n) complex(modulus = rlnorm(n), argument = runif(n, 0, 2 * pi)) set.seed(14L) (X <- new("zgRMatrix", Dim = c(3L, 5L), Dimnames = list(A = paste0("a", 1:3), B = paste0("b", 1:5)), p = c(0L, 1L, 2L, 5L), j = c(1L, 0L, 0L, 1L, 4L), x = round(rcplx(5L), 2L))) ( ctX <- ct (X)) # compressed sparse row (.ctX <- .ctCRT(X)) # compressed sparse column stopifnot(identical(dim(ctX), dim(X)[2:1]), identical(dimnames(ctX), dimnames(X)[2:1]), identical(X, ct ( ctX)), identical(X, .ctCRT(.ctX)), identical( ctX, as(.ctX, "RsparseMatrix")), identical(.ctX, as( ctX, "CsparseMatrix")), identical(ctX, .ctCRT(X, lazy = FALSE))) (S <- crossprod(X, trans = "C")) # formally Hermitian (ctS <- ct(S)) # *output* is identical but stored triangle is different stopifnot(is(S, "zpRMatrix"), all.equal(S, ctS, tolerance = 0), S@uplo == "U", ctS@uplo == "L", identical(S, ct(ctS)))
Classes BunchKaufman and pBunchKaufman represent
Bunch-Kaufman factorizations of real,
symmetric matrices , having the general form
where
and are symmetric, block diagonal
matrices composed of and
or diagonal blocks;
is the product of row-permuted unit upper triangular
matrices, each having nonzero entries above the diagonal in 1 or 2 columns;
and
is the product of row-permuted unit lower triangular
matrices, each having nonzero entries below the diagonal in 1 or 2 columns.
These classes store the nonzero entries of the
or factors,
which are individually sparse,
in a dense format as a vector of length
(BunchKaufman) or
(pBunchKaufman),
the latter giving the “packed” representation.
Dim, Dimnames
inherited from virtual class
MatrixFactorization.
uploa string, either "U" or "L",
indicating which triangle (upper or lower) of the factorized
symmetric matrix was used to compute the factorization and
in turn how the x slot is partitioned.
xa numeric vector of length n*n
(BunchKaufman) or n*(n+1)/2 (pBunchKaufman),
where n=Dim[1].
The details of the representation are specified by the manual
for LAPACK routines dsytrf and dsptrf.
perman integer vector of length n=Dim[1]
specifying row and column interchanges as described in the manual
for LAPACK routines dsytrf and dsptrf.
Class BunchKaufmanFactorization, directly.
Class MatrixFactorization, by class
BunchKaufmanFactorization, distance 2.
Objects can be generated directly by calls of the form
new("BunchKaufman", ...) or new("pBunchKaufman", ...),
but they are more typically obtained as the value of
BunchKaufman(x) for x inheriting from
dsyMatrix or dspMatrix.
coercesignature(from = "BunchKaufman", to = "dtrMatrix"):
returns a dtrMatrix, useful for inspecting
the internal representation of the factorization; see ‘Note’.
coercesignature(from = "pBunchKaufman", to = "dtpMatrix"):
returns a dtpMatrix, useful for inspecting
the internal representation of the factorization; see ‘Note’.
determinantsignature(x = "p?BunchKaufman", logarithm = "logical"):
computes the determinant of the factorized matrix
or its logarithm.
expand1signature(x = "p?BunchKaufman"):
see expand1-methods.
expand2signature(x = "p?BunchKaufman"):
see expand2-methods.
solvesignature(a = "p?BunchKaufman", b = .):
see solve-methods.
In Matrix < 1.6-0, class BunchKaufman extended
dtrMatrix and class pBunchKaufman extended
dtpMatrix, reflecting the fact that the internal
representation of the factorization is fundamentally triangular:
there are “parameters”, and these
can be arranged systematically to form an
triangular matrix.
Matrix 1.6-0 removed these extensions so that methods
would no longer be inherited from dtrMatrix and dtpMatrix.
The availability of such methods gave the wrong impression that
BunchKaufman and pBunchKaufman represent a (singular)
matrix, when in fact they represent an ordered set of matrix factors.
The coercions as(., "dtrMatrix") and as(., "dtpMatrix")
are provided for users who understand the caveats.
The LAPACK source code, including documentation; see https://netlib.org/lapack/double/dsytrf.f and https://netlib.org/lapack/double/dsptrf.f.
Golub, G. H., & Van Loan, C. F. (2013). Matrix computations (4th ed.). Johns Hopkins University Press. doi:10.56021/9781421407944
Class dsyMatrix and its packed counterpart.
Generic functions BunchKaufman,
expand1, and expand2.
showClass("denseBunchKaufman") set.seed(1) n <- 6L (A <- forceSymmetric(Matrix(rnorm(n * n), n, n))) ## With dimnames, to see that they are propagated : dimnames(A) <- rep.int(list(paste0("x", seq_len(n))), 2L) (bk.A <- BunchKaufman(A)) str(e.bk.A <- expand2(bk.A, complete = FALSE), max.level = 2L) str(E.bk.A <- expand2(bk.A, complete = TRUE), max.level = 2L) ## Underlying LAPACK representation (m.bk.A <- as(bk.A, "dtrMatrix")) stopifnot(identical(as(m.bk.A, "matrix"), `dim<-`(bk.A@x, bk.A@Dim))) ## Number of factors is 2*b+1, b <= n, which can be nontrivial ... (b <- (length(E.bk.A) - 1L) %/% 2L) ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) ## A ~ U DU U', U := prod(Pk Uk) in floating point stopifnot(exprs = { identical(names(e.bk.A), c("U", "DU", "U.")) identical(e.bk.A[["U" ]], Reduce(`%*%`, E.bk.A[seq_len(b)])) identical(e.bk.A[["U."]], t(e.bk.A[["U"]])) ae1(A, with(e.bk.A, U %*% DU %*% U.)) }) ## Factorization handled as factorized matrix b <- rnorm(n) stopifnot(identical(det(A), det(bk.A)), identical(solve(A, b), solve(bk.A, b)))showClass("denseBunchKaufman") set.seed(1) n <- 6L (A <- forceSymmetric(Matrix(rnorm(n * n), n, n))) ## With dimnames, to see that they are propagated : dimnames(A) <- rep.int(list(paste0("x", seq_len(n))), 2L) (bk.A <- BunchKaufman(A)) str(e.bk.A <- expand2(bk.A, complete = FALSE), max.level = 2L) str(E.bk.A <- expand2(bk.A, complete = TRUE), max.level = 2L) ## Underlying LAPACK representation (m.bk.A <- as(bk.A, "dtrMatrix")) stopifnot(identical(as(m.bk.A, "matrix"), `dim<-`(bk.A@x, bk.A@Dim))) ## Number of factors is 2*b+1, b <= n, which can be nontrivial ... (b <- (length(E.bk.A) - 1L) %/% 2L) ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) ## A ~ U DU U', U := prod(Pk Uk) in floating point stopifnot(exprs = { identical(names(e.bk.A), c("U", "DU", "U.")) identical(e.bk.A[["U" ]], Reduce(`%*%`, E.bk.A[seq_len(b)])) identical(e.bk.A[["U."]], t(e.bk.A[["U"]])) ae1(A, with(e.bk.A, U %*% DU %*% U.)) }) ## Factorization handled as factorized matrix b <- rnorm(n) stopifnot(identical(det(A), det(bk.A)), identical(solve(A, b), solve(bk.A, b)))
Classes Cholesky and pCholesky represent
dense, pivoted Cholesky factorizations of
real, symmetric, positive semidefinite matrices ,
having the general form
or (equivalently)
where
is a permutation matrix,
is a unit lower triangular matrix,
is a non-negative diagonal matrix, and
.
These classes store the entries of the Cholesky factor
or its transpose in a dense format as
a vector of length (Cholesky) or
(pCholesky), the latter
giving the “packed” representation.
Dim, Dimnames
inherited from virtual class
MatrixFactorization.
uploa string, either "U" or "L",
indicating which triangle (upper or lower) of the factorized
symmetric matrix was used to compute the factorization and
in turn whether x stores or .
xa numeric vector of length n*n
(Cholesky) or n*(n+1)/2 (pCholesky),
where n=Dim[1], listing the entries of the Cholesky
factor or its transpose in column-major
order.
perma 1-based integer vector of length Dim[1]
specifying the permutation applied to the rows and columns
of the factorized matrix. perm of length 0 is valid and
equivalent to the identity permutation, implying no pivoting.
Class CholeskyFactorization, directly.
Class MatrixFactorization, by class
CholeskyFactorization, distance 2.
Objects can be generated directly by calls of the form
new("Cholesky", ...) or new("pCholesky", ...),
but they are more typically obtained as the value of
Cholesky(x) for x inheriting from
dsyMatrix or dspMatrix
(often the subclasses of those reserved for positive
semidefinite matrices, namely dpoMatrix
and dppMatrix).
coercesignature(from = "Cholesky", to = "dtrMatrix"):
returns a dtrMatrix representing
the Cholesky factor or its transpose ;
see ‘Note’.
coercesignature(from = "pCholesky", to = "dtpMatrix"):
returns a dtpMatrix representing
the Cholesky factor or its transpose ;
see ‘Note’.
determinantsignature(x = "p?Cholesky", logarithm = "logical"):
computes the determinant of the factorized matrix
or its logarithm.
diagsignature(x = "p?Cholesky"):
returns a numeric vector of length containing the diagonal
elements of , which are the squared diagonal elements of
.
expand1signature(x = "p?Cholesky"):
see expand1-methods.
expand2signature(x = "p?Cholesky"):
see expand2-methods.
solvesignature(a = "p?Cholesky", b = .):
see solve-methods.
In Matrix < 1.6-0, class Cholesky extended
dtrMatrix and class pCholesky extended
dtpMatrix, reflecting the fact that the factor
is indeed a triangular matrix.
Matrix 1.6-0 removed these extensions so that methods
would no longer be inherited from dtrMatrix and dtpMatrix.
The availability of such methods gave the wrong impression that
Cholesky and pCholesky represent a (singular)
matrix, when in fact they represent an ordered set of matrix factors.
The coercions as(., "dtrMatrix") and as(., "dtpMatrix")
are provided for users who understand the caveats.
The LAPACK source code, including documentation; see https://netlib.org/lapack/double/dpstrf.f, https://netlib.org/lapack/double/dpotrf.f, and https://netlib.org/lapack/double/dpptrf.f.
Lucas, C. (2004). LAPACK-style codes for level 2 and 3 pivoted Cholesky factorizations. LAPACK Working Note, Number 161. https://www.netlib.org/lapack/lawnspdf/lawn161.pdf
Golub, G. H., & Van Loan, C. F. (2013). Matrix computations (4th ed.). Johns Hopkins University Press. doi:10.56021/9781421407944
Class CHMfactor for sparse Cholesky factorizations.
Classes dpoMatrix and dppMatrix.
Generic functions Cholesky,
expand1 and expand2.
showClass("denseCholesky") set.seed(1) m <- 30L n <- 6L (A <- crossprod(Matrix(rnorm(m * n), m, n))) ## With dimnames, to see that they are propagated : dimnames(A) <- dn <- rep.int(list(paste0("x", seq_len(n))), 2L) (ch.A <- Cholesky(A)) # pivoted, by default str(e.ch.A <- expand2(ch.A, LDL = TRUE), max.level = 2L) str(E.ch.A <- expand2(ch.A, LDL = FALSE), max.level = 2L) ## Underlying LAPACK representation (m.ch.A <- as(ch.A, "dtrMatrix")) # which is L', not L, because A@uplo == "U" stopifnot(identical(as(m.ch.A, "matrix"), `dim<-`(ch.A@x, ch.A@Dim))) ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) ## A ~ P1' L1 D L1' P1 ~ P1' L L' P1 in floating point stopifnot(exprs = { identical(names(e.ch.A), c("P1.", "L1", "D", "L1.", "P1")) identical(names(E.ch.A), c("P1.", "L" , "L." , "P1")) identical(e.ch.A[["P1"]], new("pMatrix", Dim = c(n, n), Dimnames = c(list(NULL), dn[2L]), margin = 2L, perm = invertPerm(ch.A@perm))) identical(e.ch.A[["P1."]], t(e.ch.A[["P1"]])) identical(e.ch.A[["L1."]], t(e.ch.A[["L1"]])) identical(E.ch.A[["L." ]], t(E.ch.A[["L" ]])) identical(e.ch.A[["D"]], Diagonal(x = diag(ch.A))) all.equal(E.ch.A[["L"]], with(e.ch.A, L1 %*% sqrt(D))) ae1(A, with(e.ch.A, P1. %*% L1 %*% D %*% L1. %*% P1)) ae1(A, with(E.ch.A, P1. %*% L %*% L. %*% P1)) ae2(A[ch.A@perm, ch.A@perm], with(e.ch.A, L1 %*% D %*% L1.)) ae2(A[ch.A@perm, ch.A@perm], with(E.ch.A, L %*% L. )) }) ## Factorization handled as factorized matrix b <- rnorm(n) all.equal(det(A), det(ch.A), tolerance = 0) all.equal(solve(A, b), solve(ch.A, b), tolerance = 0) ## For identical results, we need the _unpivoted_ factorization ## computed by det(A) and solve(A, b) (ch.A.nopivot <- Cholesky(A, perm = FALSE)) stopifnot(identical(det(A), det(ch.A.nopivot)), identical(solve(A, b), solve(ch.A.nopivot, b)))showClass("denseCholesky") set.seed(1) m <- 30L n <- 6L (A <- crossprod(Matrix(rnorm(m * n), m, n))) ## With dimnames, to see that they are propagated : dimnames(A) <- dn <- rep.int(list(paste0("x", seq_len(n))), 2L) (ch.A <- Cholesky(A)) # pivoted, by default str(e.ch.A <- expand2(ch.A, LDL = TRUE), max.level = 2L) str(E.ch.A <- expand2(ch.A, LDL = FALSE), max.level = 2L) ## Underlying LAPACK representation (m.ch.A <- as(ch.A, "dtrMatrix")) # which is L', not L, because A@uplo == "U" stopifnot(identical(as(m.ch.A, "matrix"), `dim<-`(ch.A@x, ch.A@Dim))) ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) ## A ~ P1' L1 D L1' P1 ~ P1' L L' P1 in floating point stopifnot(exprs = { identical(names(e.ch.A), c("P1.", "L1", "D", "L1.", "P1")) identical(names(E.ch.A), c("P1.", "L" , "L." , "P1")) identical(e.ch.A[["P1"]], new("pMatrix", Dim = c(n, n), Dimnames = c(list(NULL), dn[2L]), margin = 2L, perm = invertPerm(ch.A@perm))) identical(e.ch.A[["P1."]], t(e.ch.A[["P1"]])) identical(e.ch.A[["L1."]], t(e.ch.A[["L1"]])) identical(E.ch.A[["L." ]], t(E.ch.A[["L" ]])) identical(e.ch.A[["D"]], Diagonal(x = diag(ch.A))) all.equal(E.ch.A[["L"]], with(e.ch.A, L1 %*% sqrt(D))) ae1(A, with(e.ch.A, P1. %*% L1 %*% D %*% L1. %*% P1)) ae1(A, with(E.ch.A, P1. %*% L %*% L. %*% P1)) ae2(A[ch.A@perm, ch.A@perm], with(e.ch.A, L1 %*% D %*% L1.)) ae2(A[ch.A@perm, ch.A@perm], with(E.ch.A, L %*% L. )) }) ## Factorization handled as factorized matrix b <- rnorm(n) all.equal(det(A), det(ch.A), tolerance = 0) all.equal(solve(A, b), solve(ch.A, b), tolerance = 0) ## For identical results, we need the _unpivoted_ factorization ## computed by det(A) and solve(A, b) (ch.A.nopivot <- Cholesky(A, perm = FALSE)) stopifnot(identical(det(A), det(ch.A.nopivot)), identical(solve(A, b), solve(ch.A.nopivot, b)))
denseLU is the class of dense, row-pivoted LU factorizations
of real matrices ,
having the general form
or (equivalently)
where
is an permutation matrix,
is an
unit lower trapezoidal matrix, and
is a
upper trapezoidal matrix. If , then the factors
and are triangular.
Dim, Dimnames
inherited from virtual class
MatrixFactorization.
xa numeric vector of length prod(Dim) storing
the triangular and factors together in a packed
format. The details of the representation are specified by the
manual for LAPACK routine dgetrf.
perman integer vector of length min(Dim)
specifying the permutation as a product of
transpositions. The corresponding permutation vector can
be obtained as asPerm(perm).
Class LU, directly.
Class MatrixFactorization, by class
LU, distance 2.
Objects can be generated directly by calls of the form
new("denseLU", ...), but they are more typically obtained
as the value of lu(x) for x inheriting from
denseMatrix (often dgeMatrix).
coercesignature(from = "denseLU", to = "dgeMatrix"):
returns a dgeMatrix with the dimensions
of the factorized matrix , equal to below the
diagonal and equal to on and above the diagonal.
determinantsignature(x = "denseLU", logarithm = "logical"):
computes the determinant of the factorized matrix
or its logarithm.
expandsignature(x = "denseLU"):
see expand-methods.
expand1signature(x = "denseLU"):
see expand1-methods.
expand2signature(x = "denseLU"):
see expand2-methods.
solvesignature(a = "denseLU", b = "missing"):
see solve-methods.
The LAPACK source code, including documentation; see https://netlib.org/lapack/double/dgetrf.f.
Golub, G. H., & Van Loan, C. F. (2013). Matrix computations (4th ed.). Johns Hopkins University Press. doi:10.56021/9781421407944
Class sparseLU for sparse LU factorizations.
Class dgeMatrix.
Generic functions lu,
expand1 and expand2.
showClass("denseLU") set.seed(1) n <- 3L (A <- Matrix(round(rnorm(n * n), 2L), n, n)) ## With dimnames, to see that they are propagated : dimnames(A) <- dn <- list(paste0("r", seq_len(n)), paste0("c", seq_len(n))) (lu.A <- lu(A)) str(e.lu.A <- expand2(lu.A), max.level = 2L) ## Underlying LAPACK representation (m.lu.A <- as(lu.A, "dgeMatrix")) # which is L and U interlaced stopifnot(identical(as(m.lu.A, "matrix"), `dim<-`(lu.A@x, lu.A@Dim))) ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) ## A ~ P1' L U in floating point stopifnot(exprs = { identical(names(e.lu.A), c("P1.", "L", "U")) identical(e.lu.A[["P1."]], new( "pMatrix", Dim = c(n, n), Dimnames = c(dn[1L], list(NULL)), margin = 1L, perm = invertPerm(asPerm(lu.A@perm)))) identical(e.lu.A[["L"]], new("dtrMatrix", Dim = c(n, n), Dimnames = list(NULL, NULL), uplo = "L", diag = "U", x = lu.A@x)) identical(e.lu.A[["U"]], new("dtrMatrix", Dim = c(n, n), Dimnames = c(list(NULL), dn[2L]), uplo = "U", diag = "N", x = lu.A@x)) ae1(A, with(e.lu.A, P1. %*% L %*% U)) ae2(A[asPerm(lu.A@perm), ], with(e.lu.A, L %*% U)) }) ## Factorization handled as factorized matrix b <- rnorm(n) stopifnot(identical(det(A), det(lu.A)), identical(solve(A, b), solve(lu.A, b)))showClass("denseLU") set.seed(1) n <- 3L (A <- Matrix(round(rnorm(n * n), 2L), n, n)) ## With dimnames, to see that they are propagated : dimnames(A) <- dn <- list(paste0("r", seq_len(n)), paste0("c", seq_len(n))) (lu.A <- lu(A)) str(e.lu.A <- expand2(lu.A), max.level = 2L) ## Underlying LAPACK representation (m.lu.A <- as(lu.A, "dgeMatrix")) # which is L and U interlaced stopifnot(identical(as(m.lu.A, "matrix"), `dim<-`(lu.A@x, lu.A@Dim))) ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) ## A ~ P1' L U in floating point stopifnot(exprs = { identical(names(e.lu.A), c("P1.", "L", "U")) identical(e.lu.A[["P1."]], new( "pMatrix", Dim = c(n, n), Dimnames = c(dn[1L], list(NULL)), margin = 1L, perm = invertPerm(asPerm(lu.A@perm)))) identical(e.lu.A[["L"]], new("dtrMatrix", Dim = c(n, n), Dimnames = list(NULL, NULL), uplo = "L", diag = "U", x = lu.A@x)) identical(e.lu.A[["U"]], new("dtrMatrix", Dim = c(n, n), Dimnames = c(list(NULL), dn[2L]), uplo = "U", diag = "N", x = lu.A@x)) ae1(A, with(e.lu.A, P1. %*% L %*% U)) ae2(A[asPerm(lu.A@perm), ], with(e.lu.A, L %*% U)) }) ## Factorization handled as factorized matrix b <- rnorm(n) stopifnot(identical(det(A), det(lu.A)), identical(solve(A, b), solve(lu.A, b)))
denseMatrix is a virtual subclass of
Matrix representing dense format matrices.
Formally, a dense format is a storage format in which the space
required to represent an matrix with
nonzero entries is not .
Dim, Dimnames
inherited from virtual superclass
Matrix.
Package Matrix defines two virtual subclasses of
denseMatrix: unpackedMatrix and
packedMatrix. These correspond to the
conventional and packed storage formats defined by LAPACK:
https://netlib.org/lapack/lug/node121.html. See those help
topics for implementation details and (recursively) further
subclasses.
“Complementary” class sparseMatrix
representing sparse (meaning not dense) format matrices.
showClass("denseMatrix")showClass("denseMatrix")
Schur is the class of Schur factorizations of
real matrices ,
having the general form
where
is an orthogonal matrix and
is a block upper triangular matrix with
or diagonal blocks
specifying the real and complex conjugate eigenvalues of .
The column vectors of are the Schur vectors of ,
and is the Schur form of .
The Schur factorization generalizes the spectral decomposition
of normal matrices , whose Schur form is block diagonal,
to arbitrary square matrices.
The matrix and its Schur form are similar
and thus have the same spectrum. The eigenvalues are computed
trivially as the eigenvalues of the diagonal blocks of .
Dim, Dimnames
inherited from virtual class
MatrixFactorization.
xa numeric vector of length prod(Dim)
storing the entries of in column-major order.
x of length 0 is value and indicates that
is diagonal with diagonal entries given by values.
vectorsa numeric vector of length prod(Dim)
storing the entries of in column-major order.
vectors of length 0 is valid and indicates that
the factorization was computed without the Schur vectors.
valuesa numeric or complex vector of length Dim[1]
storing the eigenvalues of the diagonal blocks of ,
which are the eigenvalues of and consequently of the
factorized matrix .
Class SchurFactorization, directly.
Class MatrixFactorization, by class
SchurFactorization, distance 2.
Objects can be generated directly by calls of the form
new("Schur", ...), but they are more typically obtained
as the value of Schur(x) for x inheriting from
Matrix (often dgeMatrix).
determinantsignature(x = "Schur", logarithm = "logical"):
computes the determinant of the factorized matrix
or its logarithm.
expand1signature(x = "Schur"):
see expand1-methods.
expand2signature(x = "Schur"):
see expand2-methods.
solvesignature(a = "Schur", b = .):
see solve-methods.
The LAPACK source code, including documentation; see https://netlib.org/lapack/double/dgees.f.
Golub, G. H., & Van Loan, C. F. (2013). Matrix computations (4th ed.). Johns Hopkins University Press. doi:10.56021/9781421407944
Class dgeMatrix.
Generic functions Schur,
expand1 and expand2.
showClass("denseSchur") set.seed(0) n <- 4L (A <- Matrix(rnorm(n * n), n, n)) ## With dimnames, to see that they are propagated : dimnames(A) <- list(paste0("r", seq_len(n)), paste0("c", seq_len(n))) (sch.A <- Schur(A)) str(e.sch.A <- expand2(sch.A), max.level = 2L) ## A ~ Q T Q' in floating point stopifnot(exprs = { identical(names(e.sch.A), c("Q", "T", "Q.")) all.equal(A, with(e.sch.A, Q %*% T %*% Q.)) }) ## Factorization handled as factorized matrix b <- rnorm(n) stopifnot(all.equal(det(A), det(sch.A)), all.equal(solve(A, b), solve(sch.A, b)))showClass("denseSchur") set.seed(0) n <- 4L (A <- Matrix(rnorm(n * n), n, n)) ## With dimnames, to see that they are propagated : dimnames(A) <- list(paste0("r", seq_len(n)), paste0("c", seq_len(n))) (sch.A <- Schur(A)) str(e.sch.A <- expand2(sch.A), max.level = 2L) ## A ~ Q T Q' in floating point stopifnot(exprs = { identical(names(e.sch.A), c("Q", "T", "Q.")) all.equal(A, with(e.sch.A, Q %*% T %*% Q.)) }) ## Factorization handled as factorized matrix b <- rnorm(n) stopifnot(all.equal(det(A), det(sch.A)), all.equal(solve(A, b), solve(sch.A, b)))
TODO.
det(x, ...) determinant(x, logarithm = TRUE, ...)det(x, ...) determinant(x, logarithm = TRUE, ...)
x |
. |
logarithm |
. |
... |
. |
(M <- Matrix(c(0, 1, 0, 0), 6, 4)) cm <- M[1:4, ] + 10 * Diagonal(4) stopifnot(all.equal(det(cm), determinant(as(cm, "matrix"), log = FALSE)$modulus, check.attributes = FALSE))(M <- Matrix(c(0, 1, 0, 0), 6, 4)) cm <- M[1:4, ] + 10 * Diagonal(4) stopifnot(all.equal(det(cm), determinant(as(cm, "matrix"), log = FALSE)$modulus, check.attributes = FALSE))
TODO.
diag(x = 1, nrow, ncol, names = TRUE) diag(x) <- valuediag(x = 1, nrow, ncol, names = TRUE) diag(x) <- value
x |
. |
nrow |
. |
ncol |
. |
names |
. |
value |
. |
(M <- Matrix(c(0, 1, 0, 0), 6, 4)) diag(M)(M <- Matrix(c(0, 1, 0, 0), 6, 4)) diag(M)
Construct a formally diagonal Matrix,
i.e., an object inheriting from virtual class
diagonalMatrix
(or, if desired, a mathematically diagonal
CsparseMatrix).
Diagonal(n, x = NULL, names = FALSE, int2dbl = ) .sparseDiagonal(n, x = NULL, uplo = "U", shape = "t", unitri = TRUE, kind, cols, int2dbl = ) .trDiagonal(n, x = NULL, uplo = "U", unitri = TRUE, kind) .symDiagonal(n, x = NULL, uplo = "U", kind)Diagonal(n, x = NULL, names = FALSE, int2dbl = ) .sparseDiagonal(n, x = NULL, uplo = "U", shape = "t", unitri = TRUE, kind, cols, int2dbl = ) .trDiagonal(n, x = NULL, uplo = "U", unitri = TRUE, kind) .symDiagonal(n, x = NULL, uplo = "U", kind)
n |
integer indicating the dimension of the (square) matrix.
If missing, then |
x |
numeric or logical vector listing values for the diagonal
entries, to be recycled as necessary. If |
names |
either |
uplo |
one of |
shape |
one of |
unitri |
logical indicating if a formally triangular result with
ones on the diagonal should be formally unit triangular, i.e.,
with |
kind |
one of |
cols |
optional integer vector with values in |
int2dbl |
|
Diagonal() returns an object inheriting from virtual class
diagonalMatrix.
.sparseDiagonal() returns a CsparseMatrix
representation of Diagonal(n, x) or, if cols is given,
of Diagonal(n, x)[, cols+1]. The precise class of the result
depends on shape and kind.
.trDiagonal() and .symDiagonal() are simple wrappers,
for .sparseDiagonal(shape = "t") and
.sparseDiagonal(shape = "s"), respectively.
.sparseDiagonal() exists primarily to leverage efficient
C-level methods available for CsparseMatrix.
Martin Maechler
the generic function diag for extraction
of the diagonal from a matrix works for all “Matrices”.
bandSparse constructs a banded sparse matrix from
its non-zero sub-/super - diagonals. band(A) returns a
band matrix containing some sub-/super - diagonals of A.
Matrix for general matrix construction;
further, class diagonalMatrix.
Diagonal(3) Diagonal(x = 10^(3:1)) Diagonal(x = (1:4) >= 2)#-> "ldiMatrix" ## Use Diagonal() + kronecker() for "repeated-block" matrices: M1 <- Matrix(0+0:5, 2,3) (M <- kronecker(Diagonal(3), M1)) (S <- crossprod(Matrix(rbinom(60, size=1, prob=0.1), 10,6))) (SI <- S + 10*.symDiagonal(6)) # sparse symmetric still stopifnot(is(SI, "dsCMatrix")) (I4 <- .sparseDiagonal(4, shape="t"))# now (2012-10) unitriangular stopifnot(I4@diag == "U", all(I4 == diag(4)))Diagonal(3) Diagonal(x = 10^(3:1)) Diagonal(x = (1:4) >= 2)#-> "ldiMatrix" ## Use Diagonal() + kronecker() for "repeated-block" matrices: M1 <- Matrix(0+0:5, 2,3) (M <- kronecker(Diagonal(3), M1)) (S <- crossprod(Matrix(rbinom(60, size=1, prob=0.1), 10,6))) (SI <- S + 10*.symDiagonal(6)) # sparse symmetric still stopifnot(is(SI, "dsCMatrix")) (I4 <- .sparseDiagonal(4, shape="t"))# now (2012-10) unitriangular stopifnot(I4@diag == "U", all(I4 == diag(4)))
diagonalMatrix is a virtual subclass of
triangularMatrix and of
indexMatrix representing diagonal matrices.
Dim, Dimnames
inherited from virtual superclass
Matrix. Dim[1] and Dim[2] must
be equal.
All direct, nonvirtual subclasses of diagonalMatrix defined in
package Matrix have two additional slots:
diaga character string, either "N" or
"U". "N" indicates that x stores the
diagonal entries of the represented matrix. "U" indicates
that the represented matrix is unit diagonal and that x is
empty.
xa vector of length n=Dim[1]=Dim[2] or 0,
conditionally (depending on diag) storing the diagonal
entries of the represented matrix.
The direct, nonvirtual subclasses of diagonalMatrix defined in
package Matrix are listed below with links to virtual
superclasses defining their data type.
| Nonvirtual subclass | Data type |
ndiMatrix |
nMatrix
|
ldiMatrix |
lMatrix
|
idiMatrix |
iMatrix
|
ddiMatrix |
dMatrix
|
zdiMatrix |
zMatrix
|
Class ndiMatrix was not defined until Matrix version
1.6-2.
Related classes
generalMatrix,
symmetricMatrix,
posdefMatrix,
triangularMatrix, and
indexMatrix representing
general (unstructured, possibly nonsquare), Hermitian or symmetric,
positive semidefinite, triangular, and index matrices. Generic
function isDiagonal for testing for testing
if a matrix is diagonal. Generic function
forceDiagonal for inducing diagonal structure.
Function Diagonal, a constructor for
diagonalMatrix objects.
I5 <- Diagonal(5) D5 <- Diagonal(x = 10*(1:5)) ## trivial (but explicitly defined) methods: stopifnot(identical(crossprod(I5), I5), identical(tcrossprod(I5), I5), identical(crossprod(I5, D5), D5), identical(tcrossprod(D5, I5), D5), identical(solve(D5), solve(D5, I5)), all.equal(D5, solve(solve(D5)), tolerance = 1e-12) ) solve(D5)# efficient as is diagonal # an unusual way to construct a band matrix: rbind2(cbind2(I5, D5), cbind2(D5, I5)) (lM <- Diagonal(x = c(TRUE,FALSE,FALSE))) str(lM)#> gory details (slots) crossprod(lM) # numeric (nM <- as(lM, "nMatrix")) crossprod(nM) # pattern sparse (d2 <- Diagonal(x = c(10,1))) str(d2) ## slightly larger in internal size: str(as(d2, "sparseMatrix")) M <- Matrix(cbind(1,2:4)) M %*% d2 #> `fast' multiplication chol(d2) # trivial stopifnot(is(cd2 <- chol(d2), "ddiMatrix"), all.equal(cd2@x, c(sqrt(10),1)))I5 <- Diagonal(5) D5 <- Diagonal(x = 10*(1:5)) ## trivial (but explicitly defined) methods: stopifnot(identical(crossprod(I5), I5), identical(tcrossprod(I5), I5), identical(crossprod(I5, D5), D5), identical(tcrossprod(D5, I5), D5), identical(solve(D5), solve(D5, I5)), all.equal(D5, solve(solve(D5)), tolerance = 1e-12) ) solve(D5)# efficient as is diagonal # an unusual way to construct a band matrix: rbind2(cbind2(I5, D5), cbind2(D5, I5)) (lM <- Diagonal(x = c(TRUE,FALSE,FALSE))) str(lM)#> gory details (slots) crossprod(lM) # numeric (nM <- as(lM, "nMatrix")) crossprod(nM) # pattern sparse (d2 <- Diagonal(x = c(10,1))) str(d2) ## slightly larger in internal size: str(as(d2, "sparseMatrix")) M <- Matrix(cbind(1,2:4)) M %*% d2 #> `fast' multiplication chol(d2) # trivial stopifnot(is(cd2 <- chol(d2), "ddiMatrix"), all.equal(cd2@x, c(sqrt(10),1)))
Transform a triangular or diagonal matrix x, i.e., of class
triangularMatrix or diagonalMatrix,
from (internally!) unit triangular (“unitriangular”) to
“general” triangular or diagonal, respectively, (diagU2N(x))
or back (diagN2U(x)).
Note that the latter, diagN2U(x), also sets the diagonal to one
in cases where diag(x) was not all one.
.diagU2N(x) and .diagN2U(x) assume without
checking that x is a triangularMatrix with
suitable diag slot ("U" and "N", respectively),
hence they should be used with care.
diagU2N(x, cl = getClassDef(class(x)), checkDense = TRUE) diagN2U(x, cl = getClassDef(class(x)), checkDense = TRUE) .diagU2N(x, cl = getClassDef(class(x)), checkDense = FALSE) .diagN2U(x, cl = getClassDef(class(x)), checkDense = FALSE)diagU2N(x, cl = getClassDef(class(x)), checkDense = TRUE) diagN2U(x, cl = getClassDef(class(x)), checkDense = TRUE) .diagU2N(x, cl = getClassDef(class(x)), checkDense = FALSE) .diagN2U(x, cl = getClassDef(class(x)), checkDense = FALSE)
x |
a |
cl |
(optional, for speedup only:) class (definition) of |
checkDense |
logical indicating if dense (see
|
The concept of unit triangular matrices with a diag slot of
"U" stems from LAPACK.
a triangular matrix of the same class but with a
different diag slot. For diagU2N (semantically) with
identical entries as x, whereas in diagN2U(x), the
off-diagonal entries are unchanged and the diagonal is set to all
1 even if it was not previously.
Such internal storage details should rarely be of relevance to the user. Hence, these functions really are rather internal utilities.
"diagonalMatrix",
"triangularMatrix",
"dtCMatrix".
D <- Diagonal(7) Dn <- diagU2N(D) (iD <- Diagonal(7, 1L, int2dbl = FALSE)) iDn <- diagU2N(iD) stopifnot(D @diag == "U", identical( D @x, numeric()), Dn@diag == "N", identical( Dn@x, rep(1, 7)) ,iDn@diag == "N", identical(iDn@x, rep(1L, 7)) , identical( D, diagN2U( Dn)) , identical(iD, diagN2U(iDn)) ) set.seed(64); (Tr <- Matrix(rpois(49, 1/4), 7, 7)) # sparse enough (T <- D + triu(Tr, k = 1)) # sparse triangular (uT <- diagN2U(T)) # "unitriangular" (t.u <- diagN2U(10*T))# changes the diagonal! stopifnot(all(T == uT), diag(t.u) == 1, T@x == 1, identical(T, diagU2N(uT))) T[upper.tri(T)] <- 5 # still "dtC" T <- diagN2U(as(T,"triangularMatrix")) inherits(T, "sparseMatrix") # TRUE ## checkDense = T / F : dT <- as(T, "denseMatrix") # (unitriangular) sT.n <- diagU2N(dT, checkDense = TRUE) # default dT.n <- .diagU2N(dT, checkDense = FALSE) # default stopifnot(is(dT.n, "denseMatrix"), is(sT.n, "sparseMatrix"), dT@diag == "U", dT.n@diag == "N", sT.n@diag == "N", all(dT == dT.n), all(dT == sT.n))D <- Diagonal(7) Dn <- diagU2N(D) (iD <- Diagonal(7, 1L, int2dbl = FALSE)) iDn <- diagU2N(iD) stopifnot(D @diag == "U", identical( D @x, numeric()), Dn@diag == "N", identical( Dn@x, rep(1, 7)) ,iDn@diag == "N", identical(iDn@x, rep(1L, 7)) , identical( D, diagN2U( Dn)) , identical(iD, diagN2U(iDn)) ) set.seed(64); (Tr <- Matrix(rpois(49, 1/4), 7, 7)) # sparse enough (T <- D + triu(Tr, k = 1)) # sparse triangular (uT <- diagN2U(T)) # "unitriangular" (t.u <- diagN2U(10*T))# changes the diagonal! stopifnot(all(T == uT), diag(t.u) == 1, T@x == 1, identical(T, diagU2N(uT))) T[upper.tri(T)] <- 5 # still "dtC" T <- diagN2U(as(T,"triangularMatrix")) inherits(T, "sparseMatrix") # TRUE ## checkDense = T / F : dT <- as(T, "denseMatrix") # (unitriangular) sT.n <- diagU2N(dT, checkDense = TRUE) # default dT.n <- .diagU2N(dT, checkDense = FALSE) # default stopifnot(is(dT.n, "denseMatrix"), is(sT.n, "sparseMatrix"), dT@diag == "U", dT.n@diag == "N", sT.n@diag == "N", all(dT == dT.n), all(dT == sT.n))
TODO.
diff(x, ...) ## S4 method for signature 'sparseVector' diff(x, lag = 1L, differences = 1L, ...)diff(x, ...) ## S4 method for signature 'sparseVector' diff(x, lag = 1L, differences = 1L, ...)
x |
. |
lag |
. |
differences |
. |
... |
. |
(M <- Matrix(c(0, 1, 0, 0), 6, 4)) diff(M)(M <- Matrix(c(0, 1, 0, 0), 6, 4)) diff(M)
TODO.
## S4 method for signature 'Matrix' dim(x) ## S4 method for signature 'MatrixFactorization' dim(x) ## S4 replacement method for signature 'sparseVector,numeric' dim(x) <- value ## S4 method for signature 'Matrix' length(x) ## S4 method for signature 'MatrixFactorization' length(x) ## S4 method for signature 'sparseVector' length(x)## S4 method for signature 'Matrix' dim(x) ## S4 method for signature 'MatrixFactorization' dim(x) ## S4 replacement method for signature 'sparseVector,numeric' dim(x) <- value ## S4 method for signature 'Matrix' length(x) ## S4 method for signature 'MatrixFactorization' length(x) ## S4 method for signature 'sparseVector' length(x)
x |
. |
value |
. |
(M <- Matrix(c(0, 1, 0, 0), 6, 4)) dim(M) ## can reshape it even : dim(M) <- c(2, 12) M stopifnot(identical(M, Matrix(c(0, 1, 0, 0), 2, 12)))(M <- Matrix(c(0, 1, 0, 0), 6, 4)) dim(M) ## can reshape it even : dim(M) <- c(2, 12) M stopifnot(identical(M, Matrix(c(0, 1, 0, 0), 2, 12)))
TODO.
## S4 method for signature 'Matrix' dimnames(x) ## S4 method for signature 'MatrixFactorization' dimnames(x) ## S4 replacement method for signature 'Matrix,list' dimnames(x) <- value ## S4 replacement method for signature 'MatrixFactorization,list' dimnames(x) <- value## S4 method for signature 'Matrix' dimnames(x) ## S4 method for signature 'MatrixFactorization' dimnames(x) ## S4 replacement method for signature 'Matrix,list' dimnames(x) <- value ## S4 replacement method for signature 'MatrixFactorization,list' dimnames(x) <- value
x |
. |
value |
. |
dimScale, rowScale, and colScale implement
D1 %*% x %*% D2, D %*% x, and x %*% D
for diagonal matrices D1, D2, and D with
diagonal entries d1, d2, and d, respectively.
Unlike the explicit products, these functions preserve dimnames(x)
and symmetry where appropriate.
dimScale(x, d1 = sqrt(1/diag(x, names = FALSE)), d2 = d1) rowScale(x, d) colScale(x, d)dimScale(x, d1 = sqrt(1/diag(x, names = FALSE)), d2 = d1) rowScale(x, d) colScale(x, d)
x |
a matrix, possibly inheriting from virtual class
|
d1, d2, d
|
numeric vectors giving factors by which to scale
the rows or columns of |
dimScale(x) (with d1 and d2 unset) is only
roughly equivalent to cov2cor(x). cov2cor
sets the diagonal entries of the result to 1 (exactly);
dimScale does not.
The result of scaling x, currently always inheriting from
virtual class dMatrix.
It inherits from triangularMatrix if and only
if x does. In the special case of dimScale(x, d1, d2)
with identical d1 and d2, it inherits from
symmetricMatrix if and only if x does.
Mikael Jagan
n <- 6L (x <- forceSymmetric(matrix(1, n, n))) dimnames(x) <- rep.int(list(letters[seq_len(n)]), 2L) d <- seq_len(n) (D <- Diagonal(x = d)) (scx <- dimScale(x, d)) # symmetry and 'dimnames' kept (mmx <- D %*% x %*% D) # symmetry and 'dimnames' lost stopifnot(identical(unname(as(scx, "generalMatrix")), mmx)) rowScale(x, d) colScale(x, d)n <- 6L (x <- forceSymmetric(matrix(1, n, n))) dimnames(x) <- rep.int(list(letters[seq_len(n)]), 2L) d <- seq_len(n) (D <- Diagonal(x = d)) (scx <- dimScale(x, d)) # symmetry and 'dimnames' kept (mmx <- D %*% x %*% D) # symmetry and 'dimnames' lost stopifnot(identical(unname(as(scx, "generalMatrix")), mmx)) rowScale(x, d) colScale(x, d)
dMatrix is a virtual subclass of Matrix
representing double precision matrices, whose data are stored using
numeric vectors of type "double". ddenseMatrix and
dsparseMatrix are virtual subclasses of dMatrix
representing its intersections with denseMatrix
and sparseMatrix.
Dim, Dimnames
inherited from virtual superclass
Matrix.
xa double vector storing matrix entries. Details such as which entries are stored vary by storage format.
The nonvirtual subclasses of dMatrix are listed below with
links to virtual superclasses defining their structure and storage
format.
| Nonvirtual subclass | Structure | Storage format |
dgeMatrix |
generalMatrix |
unpackedMatrix
|
dsyMatrix |
symmetricMatrix |
unpackedMatrix
|
dpoMatrix |
posdefMatrix |
unpackedMatrix
|
dtrMatrix |
triangularMatrix |
unpackedMatrix
|
dspMatrix |
symmetricMatrix |
packedMatrix
|
dppMatrix |
posdefMatrix |
packedMatrix
|
dtpMatrix |
triangularMatrix |
packedMatrix
|
dgCMatrix |
generalMatrix |
CsparseMatrix
|
dsCMatrix |
symmetricMatrix |
CsparseMatrix
|
dpCMatrix |
posdefMatrix |
CsparseMatrix
|
dtCMatrix |
triangularMatrix |
CsparseMatrix
|
dgRMatrix |
generalMatrix |
RsparseMatrix
|
dsRMatrix |
symmetricMatrix |
RsparseMatrix
|
dpRMatrix |
posdefMatrix |
RsparseMatrix
|
dtRMatrix |
triangularMatrix |
RsparseMatrix
|
dgTMatrix |
generalMatrix |
TsparseMatrix
|
dsTMatrix |
symmetricMatrix |
TsparseMatrix
|
dpTMatrix |
posdefMatrix |
TsparseMatrix
|
dtTMatrix |
triangularMatrix |
TsparseMatrix
|
ddiMatrix |
diagonalMatrix |
unnamed
|
Classes dpCMatrix, dpRMatrix, and dpTMatrix
were not defined until Matrix version 1.8-0.
“Sister” classes nMatrix,
lMatrix, iMatrix, and
zMatrix representing boolean, logical, integer,
and complex matrices.
showClass("dMatrix") set.seed(101) round(Matrix(rnorm(28), 4, 7), 2) M <- Matrix(rlnorm(56, sd = 10), 4, 14) (M. <- zapsmall(M)) table(as.logical(M. == 0)) showClass("ddenseMatrix") showMethods(class = "ddenseMatrix", where = "package:Matrix") showClass("dsparseMatrix")showClass("dMatrix") set.seed(101) round(Matrix(rnorm(28), 4, 7), 2) M <- Matrix(rlnorm(56, sd = 10), 4, 14) (M. <- zapsmall(M)) table(as.logical(M. == 0)) showClass("ddenseMatrix") showMethods(class = "ddenseMatrix", where = "package:Matrix") showClass("dsparseMatrix")
For any (typically) sparse matrix x
compute the Dulmage-Mendelsohn row and columns permutations which at
first splits the rows and m columns into coarse partitions
each; and then a finer one, reordering rows and columns such that the
permutated matrix is “as upper triangular” as possible.
dmperm(x, nAns = 6L, seed = 0L)dmperm(x, nAns = 6L, seed = 0L)
x |
a typically sparse matrix; internally coerced to either
|
nAns |
an integer specifying the |
seed |
an integer code in -1,0,1; determining the (initial)
permutation; by default, |
See the book section by Tim Davis; page 122–127, in the References.
a named list with (by default) 6 components,
p |
integer vector with the permutation |
q |
integer vector with the permutation |
r |
integer vector of length |
s |
integer vector of length |
rr5 |
integer vector of length 5, defining the coarse row decomposition. |
cc5 |
integer vector of length 5, defining the coarse column decomposition. |
Martin Maechler, with a lot of “encouragement” by Mauricio Vargas.
Section 7.4 Dulmage-Mendelsohn decomposition, pp. 122 ff of
Timothy A. Davis (2006)
Direct Methods for Sparse Linear Systems, SIAM Series
“Fundamentals of Algorithms”.
Schur, the class of permutation matrices; "pMatrix".
set.seed(17) (S9 <- rsparsematrix(9, 9, nnz = 10, symmetric=TRUE)) # dsCMatrix str( dm9 <- dmperm(S9) ) (S9p <- with(dm9, S9[p, q])) ## looks good, but *not* quite upper triangular; these, too: str( dm9.0 <- dmperm(S9, seed=-1)) # non-random too. str( dm9_1 <- dmperm(S9, seed= 1)) # a random one ## The last two permutations differ, but have the same effect! (S9p0 <- with(dm9.0, S9[p, q])) # .. hmm .. stopifnot(all.equal(S9p0, S9p))# same as as default, but different from the random one set.seed(11) (M <- triu(rsparsematrix(9,11, 1/4))) dM <- dmperm(M); with(dM, M[p, q]) (Mp <- M[sample.int(nrow(M)), sample.int(ncol(M))]) dMp <- dmperm(Mp); with(dMp, Mp[p, q]) set.seed(7) (n7 <- rsparsematrix(5, 12, nnz = 10, rand.x = NULL)) str( dm.7 <- dmperm(n7) ) stopifnot(exprs = { lengths(dm.7[1:2]) == dim(n7) identical(dm.7, dmperm(as(n7, "dMatrix"))) identical(dm.7[1:4], dmperm(n7, nAns=4)) identical(dm.7[1:2], dmperm(n7, nAns=2)) })set.seed(17) (S9 <- rsparsematrix(9, 9, nnz = 10, symmetric=TRUE)) # dsCMatrix str( dm9 <- dmperm(S9) ) (S9p <- with(dm9, S9[p, q])) ## looks good, but *not* quite upper triangular; these, too: str( dm9.0 <- dmperm(S9, seed=-1)) # non-random too. str( dm9_1 <- dmperm(S9, seed= 1)) # a random one ## The last two permutations differ, but have the same effect! (S9p0 <- with(dm9.0, S9[p, q])) # .. hmm .. stopifnot(all.equal(S9p0, S9p))# same as as default, but different from the random one set.seed(11) (M <- triu(rsparsematrix(9,11, 1/4))) dM <- dmperm(M); with(dM, M[p, q]) (Mp <- M[sample.int(nrow(M)), sample.int(ncol(M))]) dMp <- dmperm(Mp); with(dMp, Mp[p, q]) set.seed(7) (n7 <- rsparsematrix(5, 12, nnz = 10, rand.x = NULL)) str( dm.7 <- dmperm(n7) ) stopifnot(exprs = { lengths(dm.7[1:2]) == dim(n7) identical(dm.7, dmperm(as(n7, "dMatrix"))) identical(dm.7[1:4], dmperm(n7, nAns=4)) identical(dm.7[1:2], dmperm(n7, nAns=2)) })
Deletes “non-structural” zeros (i.e., zeros stored explicitly, in memory) from a sparse matrix and returns the result.
drop0(x, tol = 0, is.Csparse = NA, give.Csparse = TRUE)drop0(x, tol = 0, is.Csparse = NA, give.Csparse = TRUE)
x |
a |
tol |
a non-negative number. If |
is.Csparse |
a logical used only if |
give.Csparse |
a logical indicating if the result must
inherit from virtual class |
A sparseMatrix, the result of deleting
non-structural zeros from x, possibly after coercion.
drop0 is sometimes called in conjunction with
zapsmall, e.g., when dealing with sparse
matrix products; see the example.
Function sparseMatrix, for constructing objects
inheriting from virtual class sparseMatrix;
nnzero.
(m <- sparseMatrix(i = 1:8, j = 2:9, x = c(0:2, 3:-1), dims = c(10L, 20L))) drop0(m) ## A larger example: t5 <- new("dtCMatrix", Dim = c(5L, 5L), uplo = "L", x = c(10, 1, 3, 10, 1, 10, 1, 10, 10), i = c(0L,2L,4L, 1L, 3L,2L,4L, 3L, 4L), p = c(0L, 3L, 5L, 7:9)) TT <- kronecker(t5, kronecker(kronecker(t5, t5), t5)) IT <- solve(TT) I. <- TT %*% IT ; nnzero(I.) # 697 ( == 625 + 72 ) I.0 <- drop0(zapsmall(I.)) ## which actually can be more efficiently achieved by I.. <- drop0(I., tol = 1e-15) stopifnot(all(I.0 == Diagonal(625)), nnzero(I..) == 625)(m <- sparseMatrix(i = 1:8, j = 2:9, x = c(0:2, 3:-1), dims = c(10L, 20L))) drop0(m) ## A larger example: t5 <- new("dtCMatrix", Dim = c(5L, 5L), uplo = "L", x = c(10, 1, 3, 10, 1, 10, 1, 10, 10), i = c(0L,2L,4L, 1L, 3L,2L,4L, 3L, 4L), p = c(0L, 3L, 5L, 7:9)) TT <- kronecker(t5, kronecker(kronecker(t5, t5), t5)) IT <- solve(TT) I. <- TT %*% IT ; nnzero(I.) # 697 ( == 625 + 72 ) I.0 <- drop0(zapsmall(I.)) ## which actually can be more efficiently achieved by I.. <- drop0(I., tol = 1e-15) stopifnot(all(I.0 == Diagonal(625)), nnzero(I..) == 625)
expand1 and expand2 construct matrix factors from
objects specifying matrix factorizations. Such objects typically
do not store the factors explicitly, employing instead a compact
representation to save memory.
expand1(x, which, ...) expand2(x, ...) expand (x, ...)expand1(x, which, ...) expand2(x, ...) expand (x, ...)
x |
a matrix factorization, typically inheriting from
virtual class |
which |
a character string indicating a matrix factor. |
... |
further arguments passed to or from methods. |
Methods for expand are retained only for backwards
compatibility with Matrix < 1.6-0. New code
should use expand1 and expand2, whose methods
provide more control and behave more consistently. Notably,
expand2 obeys the rule that the product of the matrix
factors in the returned list should reproduce
(within some tolerance) the factorized matrix,
including its dimnames.
Hence if x is a matrix and y is its factorization,
then
all.equal(as(x, "matrix"), as(Reduce(`%*%`, expand2(y)), "matrix"))
should in most cases return TRUE.
expand1 returns an object inheriting from virtual class
Matrix, representing the factor indicated
by which, always without row and column names.
expand2 returns a list of factors, typically with names
using conventional notation, as in list(L=, U=).
The first and last factors get the row and column names of the
factorized matrix, which are preserved in the Dimnames
slot of x.
The following table lists methods for expand1 together with
allowed values of argument which.
class(x) |
which
|
Schur |
c("Q", "T", "Q.")
|
denseLU |
c("P1", "P1.", "L", "U")
|
sparseLU |
c("P1", "P1.", "P2", "P2.", "L", "U")
|
sparseQR |
c("P1", "P1.", "P2", "P2.", "Q", "Q1", "R", "R1")
|
BunchKaufman, pBunchKaufman |
c("U", "DU", "U.", "L", "DL", "L.")
|
Cholesky, pCholesky |
c("P1", "P1.", "L1", "D", "L1.", "L", "L.")
|
CHMsimpl, CHMsimpl |
c("P1", "P1.", "L1", "D", "L1.", "L", "L.")
|
Methods for expand2 and expand are described
below. Factor names and classes apply also to expand1.
expand2signature(x = "CHMsimpl"):
expands the factorization
as list(P1., L1, D, L1., P1) (the default)
or as list(P1., L, L., P1),
depending on optional logical argument LDL.
P1 and P1. are pMatrix,
L1, L1., L, and L. are
dtCMatrix,
and D is a ddiMatrix.
expand2signature(x = "CHMsuper"):
as CHMsimpl, but the triangular factors are
stored as dgCMatrix.
expand2signature(x = "p?Cholesky"):
expands the factorization
as list(L1, D, L1.) (the default) or as list(L, L.),
depending on optional logical argument LDL.
L1, L1., L, and L. are
dtrMatrix or dtpMatrix,
and D is a ddiMatrix.
expand2signature(x = "p?BunchKaufman"):
expands the factorization
where
and
as list(U, DU, U.) or list(L, DL, L.),
depending on x@uplo. If optional argument complete
is TRUE, then an unnamed list giving the full expansion
with or matrix
factors is returned instead.
are represented as pMatrix,
and are represented as
dtCMatrix, and
and are represented as
dsCMatrix.
expand2signature(x = "Schur"):
expands the factorization
as list(Q, T, Q.).
Q and Q. are x@Q and t(x@Q)
modulo Dimnames, and T is x@T.
expand2signature(x = "sparseLU"):
expands the factorization
as list(P1., L, U, P2.).
P1. and P2. are pMatrix,
and L and U are dtCMatrix.
expand2signature(x = "denseLU"):
expands the factorization
as list(P1., L, U).
P1. is a pMatrix,
and L and U are dtrMatrix
if square and dgeMatrix otherwise.
expand2signature(x = "sparseQR"):
expands the factorization
as list(P1., Q, R, P2.) or list(P1., Q1, R1, P2.),
depending on optional logical argument complete.
P1. and P2. are pMatrix,
Q and Q1 are dgeMatrix,
R is a dgCMatrix,
and R1 is a dtCMatrix.
expandsignature(x = "CHMfactor"):
as expand2, but returning list(P, L).
expand(x)[["P"]] and expand2(x)[["P1"]]
represent the same permutation matrix
but have opposite margin slots and inverted
perm slots. The components of expand(x)
do not preserve x@Dimnames.
expandsignature(x = "sparseLU"):
as expand2, but returning list(P, L, U, Q).
expand(x)[["Q"]] and expand2(x)[["P2."]]
represent the same permutation matrix
but have opposite margin slots and inverted
perm slots. expand(x)[["P"]] represents
the permutation matrix rather than its
transpose ; it is expand2(x)[["P1."]]
with an inverted perm slot. expand(x)[["L"]]
and expand2(x)[["L"]] represent the same unit lower
triangular matrix , but with diag slot equal
to "N" and "U", respectively.
expand(x)[["L"]] and expand(x)[["U"]]
store the permuted first and second components of
x@Dimnames in their Dimnames slots.
expandsignature(x = "denseLU"):
as expand2, but returning list(L, U, P).
expand(x)[["P"]] and expand2(x)[["P1."]]
are identical modulo Dimnames. The components
of expand(x) do not preserve x@Dimnames.
The virtual class MatrixFactorization
of matrix factorizations.
Generic functions Cholesky, BunchKaufman,
Schur, lu, and qr for
computing factorizations.
showMethods("expand1", inherited = FALSE) showMethods("expand2", inherited = FALSE) set.seed(0) (A <- Matrix(rnorm(9L, 0, 10), 3L, 3L)) (lu.A <- lu(A)) (e.lu.A <- expand2(lu.A)) stopifnot(exprs = { is.list(e.lu.A) identical(names(e.lu.A), c("P1.", "L", "U")) all(sapply(e.lu.A, is, "Matrix")) all.equal(as(A, "matrix"), as(Reduce(`%*%`, e.lu.A), "matrix")) }) ## 'expand1' and 'expand2' give equivalent results modulo ## dimnames and representation of permutation matrices; ## see also function 'alt' in example("Cholesky-methods") (a1 <- sapply(names(e.lu.A), expand1, x = lu.A, simplify = FALSE)) all.equal(a1, e.lu.A) ## see help("denseLU-class") and others for more examplesshowMethods("expand1", inherited = FALSE) showMethods("expand2", inherited = FALSE) set.seed(0) (A <- Matrix(rnorm(9L, 0, 10), 3L, 3L)) (lu.A <- lu(A)) (e.lu.A <- expand2(lu.A)) stopifnot(exprs = { is.list(e.lu.A) identical(names(e.lu.A), c("P1.", "L", "U")) all(sapply(e.lu.A, is, "Matrix")) all.equal(as(A, "matrix"), as(Reduce(`%*%`, e.lu.A), "matrix")) }) ## 'expand1' and 'expand2' give equivalent results modulo ## dimnames and representation of permutation matrices; ## see also function 'alt' in example("Cholesky-methods") (a1 <- sapply(names(e.lu.A), expand1, x = lu.A, simplify = FALSE)) all.equal(a1, e.lu.A) ## see help("denseLU-class") and others for more examples
Compute the exponential of a matrix.
expm(x)expm(x)
x |
a matrix, typically inheriting from the
|
The exponential of a matrix is defined as the infinite Taylor
series expm(A) = I + A + A^2/2! + A^3/3! + ... (although this is
definitely not the way to compute it). The method for the
dgeMatrix class uses Ward's diagonal Pade' approximation with
three step preconditioning, a recommendation from
Moler & Van Loan (1978) “Nineteen dubious ways...”.
The matrix exponential of x.
This is a translation of the implementation of the corresponding Octave function contributed to the Octave project by A. Scottedward Hodel [email protected]. A bug in there has been fixed by Martin Maechler.
https://en.wikipedia.org/wiki/Matrix_exponential
Cleve Moler and Charles Van Loan (2003) Nineteen dubious ways to compute the exponential of a matrix, twenty-five years later. SIAM Review 45, 1, 3–49. doi:10.1137/S00361445024180
for historical reference mostly:
Moler, C. and Van Loan, C. (1978)
Nineteen dubious ways to compute the exponential of a matrix.
SIAM Review 20, 4, 801–836.
doi:10.1137/1020098
Eric W. Weisstein et al. (1999) Matrix Exponential. From MathWorld, https://mathworld.wolfram.com/MatrixExponential.html
Package expm, which provides newer (in some cases
faster, more accurate) algorithms for computing the matrix
exponential via its own (non-generic) function expm().
expm also implements logm(), sqrtm(), etc.
Generic function Schur.
(m1 <- Matrix(c(1,0,1,1), ncol = 2)) (e1 <- expm(m1)) ; e <- exp(1) stopifnot(all.equal(e1@x, c(e,0,e,e), tolerance = 1e-15)) (m2 <- Matrix(c(-49, -64, 24, 31), ncol = 2)) (e2 <- expm(m2)) (m3 <- Matrix(cbind(0,rbind(6*diag(3),0))))# sparse! (e3 <- expm(m3)) # upper triangular(m1 <- Matrix(c(1,0,1,1), ncol = 2)) (e1 <- expm(m1)) ; e <- exp(1) stopifnot(all.equal(e1@x, c(e,0,e,e), tolerance = 1e-15)) (m2 <- Matrix(c(-49, -64, 24, 31), ncol = 2)) (e2 <- expm(m2)) (m3 <- Matrix(cbind(0,rbind(6*diag(3),0))))# sparse! (e3 <- expm(m3)) # upper triangular
Read matrices stored in the Harwell-Boeing or MatrixMarket formats
or write sparseMatrix objects to one of these
formats.
readHB(file) readMM(file) writeMM(obj, file, ...)readHB(file) readMM(file) writeMM(obj, file, ...)
obj |
a real sparse matrix |
file |
for Alternatively, |
... |
optional additional arguments. Currently none are used in any methods. |
The readHB and readMM functions return an object that
inherits from the "Matrix" class. Methods for the
writeMM generic functions usually return
NULL and, as a side effect, the matrix obj is
written to file in the MatrixMarket format (writeMM).
The Harwell-Boeing format is older and less flexible than the
MatrixMarket format. The function writeHB was deprecated and
has now been removed. Please use writeMM instead.
Note that these formats do not know anything about
dimnames, hence these are dropped by writeMM().
A very simple way to export small sparse matrices S, is to use
summary(S) which returns a data.frame with
columns i, j, and possibly x, see summary in
sparseMatrix-class, and an example below.
https://math.nist.gov/MatrixMarket/
str(pores <- readMM(system.file("external/pores_1.mtx", package = "Matrix"))) str(utm <- readHB(system.file("external/utm300.rua" , package = "Matrix"))) str(lundA <- readMM(system.file("external/lund_a.mtx" , package = "Matrix"))) str(lundA <- readHB(system.file("external/lund_a.rsa" , package = "Matrix"))) ## https://math.nist.gov/MatrixMarket/data/Harwell-Boeing/counterx/counterx.htm str(jgl <- readMM(system.file("external/jgl009.mtx" , package = "Matrix"))) ## NOTE: The following examples take quite some time ## ---- even on a fast internet connection: if(FALSE) { ## The URL has been corrected, but we need an untar step: u. <- url("https://www.cise.ufl.edu/research/sparse/RB/Boeing/msc00726.tar.gz") str(sm <- readHB(gzcon(u.))) } data(KNex, package = "Matrix") ## Store as MatrixMarket (".mtx") file, here inside temporary dir./folder: (MMfile <- file.path(tempdir(), "mmMM.mtx")) writeMM(KNex$mm, file=MMfile) file.info(MMfile)[,c("size", "ctime")] # (some confirmation of the file's) ## very simple export - in triplet format - to text file: data(CAex, package = "Matrix") s.CA <- summary(CAex) s.CA # shows (i, j, x) [columns of a data frame] message("writing to ", outf <- tempfile()) write.table(s.CA, file = outf, row.names=FALSE) ## and read it back -- showing off sparseMatrix(): str(dd <- read.table(outf, header=TRUE)) ## has columns (i, j, x) -> we can use via do.call() as arguments to sparseMatrix(): mm <- do.call(sparseMatrix, dd) stopifnot(all.equal(mm, CAex, tolerance=1e-15))str(pores <- readMM(system.file("external/pores_1.mtx", package = "Matrix"))) str(utm <- readHB(system.file("external/utm300.rua" , package = "Matrix"))) str(lundA <- readMM(system.file("external/lund_a.mtx" , package = "Matrix"))) str(lundA <- readHB(system.file("external/lund_a.rsa" , package = "Matrix"))) ## https://math.nist.gov/MatrixMarket/data/Harwell-Boeing/counterx/counterx.htm str(jgl <- readMM(system.file("external/jgl009.mtx" , package = "Matrix"))) ## NOTE: The following examples take quite some time ## ---- even on a fast internet connection: if(FALSE) { ## The URL has been corrected, but we need an untar step: u. <- url("https://www.cise.ufl.edu/research/sparse/RB/Boeing/msc00726.tar.gz") str(sm <- readHB(gzcon(u.))) } data(KNex, package = "Matrix") ## Store as MatrixMarket (".mtx") file, here inside temporary dir./folder: (MMfile <- file.path(tempdir(), "mmMM.mtx")) writeMM(KNex$mm, file=MMfile) file.info(MMfile)[,c("size", "ctime")] # (some confirmation of the file's) ## very simple export - in triplet format - to text file: data(CAex, package = "Matrix") s.CA <- summary(CAex) s.CA # shows (i, j, x) [columns of a data frame] message("writing to ", outf <- tempfile()) write.table(s.CA, file = outf, row.names=FALSE) ## and read it back -- showing off sparseMatrix(): str(dd <- read.table(outf, header=TRUE)) ## has columns (i, j, x) -> we can use via do.call() as arguments to sparseMatrix(): mm <- do.call(sparseMatrix, dd) stopifnot(all.equal(mm, CAex, tolerance=1e-15))
Multiplies a matrix or vector on the left or right by a factor from a matrix factorization or its transpose.
facmul(x, factor, y, trans = FALSE, left = TRUE, ...)facmul(x, factor, y, trans = FALSE, left = TRUE, ...)
x |
a |
factor |
a character string indicating a factor in the
factorization represented by |
y |
a matrix or vector to be multiplied on the left or right by the factor or its transpose. |
trans |
a logical indicating if the transpose of the factor should be used, rather than the factor itself. |
left |
a logical indicating if the |
... |
further arguments passed to or from methods. |
facmul is experimental and currently no methods are
exported from Matrix.
The value of op(M) %*% y or y %*% op(M),
depending on left, where M is the factor
(always without dimnames) and op(M)
is M or t(M), depending on trans.
## Conceptually, methods for 'facmul' _would_ behave as follows ... ## Not run: n <- 3L x <- lu(Matrix(rnorm(n * n), n, n)) y <- rnorm(n) L <- unname(expand2(x)[[nm <- "L"]]) stopifnot(exprs = { all.equal(facmul(x, nm, y, trans = FALSE, left = TRUE), L %*% y) all.equal(facmul(x, nm, y, trans = FALSE, left = FALSE), y %*% L) all.equal(facmul(x, nm, y, trans = TRUE, left = TRUE), crossprod(L, y)) all.equal(facmul(x, nm, y, trans = TRUE, left = FALSE), tcrossprod(y, L)) }) ## End(Not run)## Conceptually, methods for 'facmul' _would_ behave as follows ... ## Not run: n <- 3L x <- lu(Matrix(rnorm(n * n), n, n)) y <- rnorm(n) L <- unname(expand2(x)[[nm <- "L"]]) stopifnot(exprs = { all.equal(facmul(x, nm, y, trans = FALSE, left = TRUE), L %*% y) all.equal(facmul(x, nm, y, trans = FALSE, left = FALSE), y %*% L) all.equal(facmul(x, nm, y, trans = TRUE, left = TRUE), crossprod(L, y)) all.equal(facmul(x, nm, y, trans = TRUE, left = FALSE), tcrossprod(y, L)) }) ## End(Not run)
“Semi-API” functions used internally by Matrix,
often to bypass S4 dispatch and avoid the associated overhead.
These are exported to provide this capability to expert users.
Typical users should continue to rely on S4 generic functions
to dispatch suitable methods, by calling,
e.g., as(., <class>) for coercions.
.M2kind(from, kind = ".", sparse = NA) .M2gen(from, kind = ".") .M2sym(from, uplo = NULL, trans = "C", ...) .M2tri(from, uplo = NULL) .M2diag(from) .M2v(from) .M2m(from) .M2unpacked(from) .M2packed(from) .M2C(from) .M2R(from) .M2T(from) .M2V(from) .m2V(from, kind = ".") .sparse2dense(from, packed = FALSE) .diag2dense(from, kind = ".", shape = "t", packed = FALSE, uplo = "U", trans = "T") .ind2dense(from, kind = "n") .m2dense(from, class = ".ge", uplo = "U", trans = "C", diag = "N", margin = 2L) .dense2sparse(from, repr = "C") .diag2sparse(from, kind = ".", shape = "t", repr = "C", uplo = "U", trans = "T") .ind2sparse(from, kind = "n", repr = ".") .m2sparse(from, class = ".gC", uplo = "U", trans = "C", diag = "N", margin = 2L) .diag.dsC(x, Chx = Cholesky(x, LDL = TRUE), res.kind = "diag") .solve.dgC.lu (a, b, tol = .Machine$double.eps, check = TRUE) .solve.dgC.qr (a, b, order = 3L, check = TRUE) .solve.dgC.chol(a, b, check = TRUE) .updateCHMfactor(object, parent, mult = 0).M2kind(from, kind = ".", sparse = NA) .M2gen(from, kind = ".") .M2sym(from, uplo = NULL, trans = "C", ...) .M2tri(from, uplo = NULL) .M2diag(from) .M2v(from) .M2m(from) .M2unpacked(from) .M2packed(from) .M2C(from) .M2R(from) .M2T(from) .M2V(from) .m2V(from, kind = ".") .sparse2dense(from, packed = FALSE) .diag2dense(from, kind = ".", shape = "t", packed = FALSE, uplo = "U", trans = "T") .ind2dense(from, kind = "n") .m2dense(from, class = ".ge", uplo = "U", trans = "C", diag = "N", margin = 2L) .dense2sparse(from, repr = "C") .diag2sparse(from, kind = ".", shape = "t", repr = "C", uplo = "U", trans = "T") .ind2sparse(from, kind = "n", repr = ".") .m2sparse(from, class = ".gC", uplo = "U", trans = "C", diag = "N", margin = 2L) .diag.dsC(x, Chx = Cholesky(x, LDL = TRUE), res.kind = "diag") .solve.dgC.lu (a, b, tol = .Machine$double.eps, check = TRUE) .solve.dgC.qr (a, b, order = 3L, check = TRUE) .solve.dgC.chol(a, b, check = TRUE) .updateCHMfactor(object, parent, mult = 0)
from, x, a, b
|
a |
kind |
a string ( |
shape |
a string ( |
repr |
a string ( |
packed |
a logical indicating if the result should
inherit from |
sparse |
a logical indicating if the result should inherit
from |
uplo |
a string ( |
trans |
a string ( |
diag |
a string ( |
margin |
an integer (1 or 2) indicating if the result should
be a 1-row matrix or a 1-column matrix in the case where |
class |
a string whose first three characters specify the class
of the result. It should match the pattern
|
... |
optional arguments passed to |
Chx |
optionally, the |
res.kind |
a string in |
tol |
see |
order |
see |
check |
a logical indicating if the first argument should be
tested for inheritance from |
object |
a Cholesky factorization inheriting from virtual class
|
parent |
|
mult |
a numeric vector of postive length. Only the first element is used, and that must be finite. |
Functions with names of the form .<A>2<B> implement coercions
from virtual class A to the “nearest” non-virtual subclass of
virtual class B, where the virtual classes are abbreviated as follows:
MVmmatrix
vvector
denseunpackedpackedsparseCRTgensymtridiagindAbbreviations should be seen as a guide, rather than as an
exact description of behaviour. Notably, .m2dense,
.m2sparse, and .m2V accept vectors that are
not matrices.
.diag.dsC(x).diag.dsC computes (or uses if Chx is supplied)
the Cholesky factorization of x as in order
to calculate one of several possible statistics from the diagonal
entries of . See res.kind under ‘Arguments’.
.solve.dgC.*(a, b).solve.dgC.lu(a, b) needs a square matrix a.
.solve.dgC.qr(a, b) needs a “long” matrix a,
with nrow(a) >= ncol(a).
.solve.dgC.chol(a, b) needs a “wide” matrix a,
with nrow(a) <= ncol(a).
All three may be used to solve sparse linear systems directly.
Only .solve.dgC.qr and .solve.dgC.chol be used
to solve sparse least squares problems.
.updateCHMfactor(object, parent, mult).updateCHMfactor updates object with the result
of Cholesky factorizing
F(parent) + mult[1] * diag(nrow(parent)),
i.e., F(parent) plus mult[1] times the identity matrix,
where F = identity if parent is a dsCMatrix
and F = tcrossprod if parent is a dgCMatrix.
The nonzero pattern of F(parent) must match
that of S if object = Cholesky(S, ...).
D. <- diag(x = c(1, 1, 2, 3, 5, 8)) D.0 <- Diagonal(x = c(0, 0, 0, 3, 5, 8)) S. <- toeplitz(as.double(1:6)) C. <- new("dgCMatrix", Dim = c(3L, 4L), p = c(0L, 1L, 1L, 1L, 3L), i = c(1L, 0L, 2L), x = c(-8, 2, 3)) stopifnot(exprs = { identical(.M2sym (D.), as(D., "symmetricMatrix")) identical(.M2tri (D.), as(D., "triangularMatrix")) identical(.M2diag(D.), as(D., "diagonalMatrix")) identical(.M2kind(C., "l"), as(C., "lMatrix")) identical(.M2kind(.sparse2dense(C.), "l"), as(as(C., "denseMatrix"), "lMatrix")) identical(.diag2sparse(D.0, ".", "t", "C"), .dense2sparse(.diag2dense(D.0, ".", "t", TRUE), "C")) identical(.M2gen(.diag2dense(D.0, ".", "s", FALSE)), .sparse2dense(.M2gen(.diag2sparse(D.0, ".", "s", "T")))) identical(S., .M2m(.m2sparse(S., ".sR", uplo = "U", trans = "C"))) identical(S. * lower.tri(S.) + diag(1, 6L), .M2m(.m2dense (S., ".tr", uplo = "L", diag = "U"))) identical(.M2R(C.), .M2R(.M2T(C.))) identical(.tCRT(C.), .M2R(t(C.))) }) A <- tcrossprod(C.)/6 + Diagonal(3, 1/3); A[1,2] <- 3; A stopifnot(exprs = { is.numeric( x. <- c(2.2, 0, -1.2) ) all.equal(x., .solve.dgC.lu(A, c(1,0,0), check=FALSE)) all.equal(x., .solve.dgC.qr(A, c(1,0,0), check=FALSE)) }) ## Solving sparse least squares: X <- rbind(A, Diagonal(3)) # design matrix X (for L.S.) Xt <- t(X) # *transposed* X (for L.S.) (y <- drop(crossprod(Xt, 1:3)) + c(-1,1)/1000) # small rand.err. str(solveCh <- .solve.dgC.chol(Xt, y, check=FALSE)) # Xt *is* dgC.. stopifnot(exprs = { all.equal(solveCh$coef, 1:3, tol = 1e-3)# rel.err ~ 1e-4 all.equal(solveCh$coef, drop(solve(tcrossprod(Xt), Xt %*% y))) all.equal(solveCh$coef, .solve.dgC.qr(X, y, check=FALSE)) })D. <- diag(x = c(1, 1, 2, 3, 5, 8)) D.0 <- Diagonal(x = c(0, 0, 0, 3, 5, 8)) S. <- toeplitz(as.double(1:6)) C. <- new("dgCMatrix", Dim = c(3L, 4L), p = c(0L, 1L, 1L, 1L, 3L), i = c(1L, 0L, 2L), x = c(-8, 2, 3)) stopifnot(exprs = { identical(.M2sym (D.), as(D., "symmetricMatrix")) identical(.M2tri (D.), as(D., "triangularMatrix")) identical(.M2diag(D.), as(D., "diagonalMatrix")) identical(.M2kind(C., "l"), as(C., "lMatrix")) identical(.M2kind(.sparse2dense(C.), "l"), as(as(C., "denseMatrix"), "lMatrix")) identical(.diag2sparse(D.0, ".", "t", "C"), .dense2sparse(.diag2dense(D.0, ".", "t", TRUE), "C")) identical(.M2gen(.diag2dense(D.0, ".", "s", FALSE)), .sparse2dense(.M2gen(.diag2sparse(D.0, ".", "s", "T")))) identical(S., .M2m(.m2sparse(S., ".sR", uplo = "U", trans = "C"))) identical(S. * lower.tri(S.) + diag(1, 6L), .M2m(.m2dense (S., ".tr", uplo = "L", diag = "U"))) identical(.M2R(C.), .M2R(.M2T(C.))) identical(.tCRT(C.), .M2R(t(C.))) }) A <- tcrossprod(C.)/6 + Diagonal(3, 1/3); A[1,2] <- 3; A stopifnot(exprs = { is.numeric( x. <- c(2.2, 0, -1.2) ) all.equal(x., .solve.dgC.lu(A, c(1,0,0), check=FALSE)) all.equal(x., .solve.dgC.qr(A, c(1,0,0), check=FALSE)) }) ## Solving sparse least squares: X <- rbind(A, Diagonal(3)) # design matrix X (for L.S.) Xt <- t(X) # *transposed* X (for L.S.) (y <- drop(crossprod(Xt, 1:3)) + c(-1,1)/1000) # small rand.err. str(solveCh <- .solve.dgC.chol(Xt, y, check=FALSE)) # Xt *is* dgC.. stopifnot(exprs = { all.equal(solveCh$coef, 1:3, tol = 1e-3)# rel.err ~ 1e-4 all.equal(solveCh$coef, drop(solve(tcrossprod(Xt), Xt %*% y))) all.equal(solveCh$coef, .solve.dgC.qr(X, y, check=FALSE)) })
Obtain a “canonical” representation of an R object as
defined by corresponding methods for isCanonical.
forceCanonical(x, ...)forceCanonical(x, ...)
x |
an R object. |
... |
optional arguments passed to methods. |
Method writers should ensure that canonicalization is idempotent.
In other words, f(f(x)) and f(x) should be identical
if f = forceCanonical.
A canonical object, typically of class class(x) or a
superclass, such that isCanonical(.) is TRUE.
utils::example(isCanonical, package = "Matrix") stopifnot(identical(unname(obj), lapply(unname(obj.), forceCanonical)))utils::example(isCanonical, package = "Matrix") stopifnot(identical(unname(obj), lapply(unname(obj.), forceCanonical)))
diagonalMatrix From the Diagonal Part of a MatrixFrom a matrix or Matrix x, use the diagonal part,
diag(x) to create a corresponding diagonalMatrix.
forceDiagonal(x, ...) ## S4 method for signature 'matrix' forceDiagonal(x, diag = NULL, ...)forceDiagonal(x, ...) ## S4 method for signature 'matrix' forceDiagonal(x, diag = NULL, ...)
x |
a |
diag |
a string, |
... |
optional arguments passed from or to other methods. |
a Matrix inheriting from
"diagonalMatrix", even when x is not diagonal.
as(x, "diagonalMatrix") does not force, but signal
an error when x is not diagonal, see isDiagonal.
forceDiagonal(diag(3)) # --> <ddiMatrix> forceDiagonal(matrix(1:4, 2))# a <idiMatrix> stopifnot(identical(forceDiagonal(Matrix(1:4, 2)), Diagonal(x = c(1, 4))))forceDiagonal(diag(3)) # --> <ddiMatrix> forceDiagonal(matrix(1:4, 2))# a <idiMatrix> stopifnot(identical(forceDiagonal(Matrix(1:4, 2)), Diagonal(x = c(1, 4))))
Returns the symmetric matrix that results from reflecting one triangle of a square matrix onto the other.
forceSymmetric(x, ...) ## S4 method for signature 'denseMatrix' forceSymmetric(x, uplo = NULL, trans = "C", ...) ## S4 method for signature 'CsparseMatrix' forceSymmetric(x, uplo = NULL, trans = "C", ...) ## S4 method for signature 'RsparseMatrix' forceSymmetric(x, uplo = NULL, trans = "C", ...) ## S4 method for signature 'TsparseMatrix' forceSymmetric(x, uplo = NULL, trans = "C", ...) ## S4 method for signature 'diagonalMatrix' forceSymmetric(x, uplo = "U", trans = "C", ...) ## S4 method for signature 'indMatrix' forceSymmetric(x, ...) ## S4 method for signature 'matrix' forceSymmetric(x, uplo = "U", trans = "C", ...)forceSymmetric(x, ...) ## S4 method for signature 'denseMatrix' forceSymmetric(x, uplo = NULL, trans = "C", ...) ## S4 method for signature 'CsparseMatrix' forceSymmetric(x, uplo = NULL, trans = "C", ...) ## S4 method for signature 'RsparseMatrix' forceSymmetric(x, uplo = NULL, trans = "C", ...) ## S4 method for signature 'TsparseMatrix' forceSymmetric(x, uplo = NULL, trans = "C", ...) ## S4 method for signature 'diagonalMatrix' forceSymmetric(x, uplo = "U", trans = "C", ...) ## S4 method for signature 'indMatrix' forceSymmetric(x, ...) ## S4 method for signature 'matrix' forceSymmetric(x, uplo = "U", trans = "C", ...)
x |
a square matrix or |
uplo |
a character string, |
trans |
a character string, |
... |
optional arguments passed from or to other methods. |
forceSymmetric(x) can be understood as a coercion to virtual
class symmetricMatrix.
However, unlike as(x, "symmetricMatrix"),
methods for forceSymmetric do not require that x
is already approximately symmetric.
An object inheriting from virtual class
symmetricMatrix,
representing a Hermitian or symmetric matrix.
isSymmetric, symmpart, skewpart.
## Hilbert matrix i <- 1:6 h6 <- 1/outer(i - 1L, i, "+") sd <- sqrt(diag(h6)) hh <- t(h6/sd)/sd # theoretically symmetric isSymmetric(hh, tol=0) # FALSE; hence try( as(hh, "symmetricMatrix") ) # fails, but this works fine: H6 <- forceSymmetric(hh) ## result can be pretty surprising: (M <- Matrix(1:36, 6)) forceSymmetric(M) # symmetric, hence very different in lower triangle (tm <- tril(M)) forceSymmetric(tm)## Hilbert matrix i <- 1:6 h6 <- 1/outer(i - 1L, i, "+") sd <- sqrt(diag(h6)) hh <- t(h6/sd)/sd # theoretically symmetric isSymmetric(hh, tol=0) # FALSE; hence try( as(hh, "symmetricMatrix") ) # fails, but this works fine: H6 <- forceSymmetric(hh) ## result can be pretty surprising: (M <- Matrix(1:36, 6)) forceSymmetric(M) # symmetric, hence very different in lower triangle (tm <- tril(M)) forceSymmetric(tm)
TODO.
forceTriangular(x, ...)forceTriangular(x, ...)
x |
a square matrix or |
... |
optional arguments passed from or to other methods. |
Utilities for formatting sparse numeric matrices in a flexible way.
These functions are used by the format and print
methods for sparse matrices and can be applied as well to standard R
matrices. Note that all arguments but the first are optional.
formatSparseM() is the main “workhorse” of
formatSpMatrix, the format method for sparse
matrices.
.formatSparseSimple() is a simple helper function, also dealing
with (short/empty) column names construction.
formatSparseM(x, zero.print = ".", align = c("fancy", "right"), m = as(x,"matrix"), asLogical=NULL, uniDiag=FALSE, digits=NULL, cx, iN0, dn = dimnames(m)) .formatSparseSimple(m, asLogical=FALSE, digits=NULL, col.names, note.dropping.colnames = TRUE, dn=dimnames(m))formatSparseM(x, zero.print = ".", align = c("fancy", "right"), m = as(x,"matrix"), asLogical=NULL, uniDiag=FALSE, digits=NULL, cx, iN0, dn = dimnames(m)) .formatSparseSimple(m, asLogical=FALSE, digits=NULL, col.names, note.dropping.colnames = TRUE, dn=dimnames(m))
x |
an R object inheriting from class |
zero.print |
character which should be used for
structural zeroes. The default |
align |
a string specifying how the |
m |
(optional) a (standard R) |
asLogical |
should the matrix be formatted as a logical matrix
(or rather as a numeric one); mostly for |
uniDiag |
logical indicating if the diagonal entries of a sparse
unit triangular or unit-diagonal matrix should be formatted as
|
digits |
significant digits to use for printing, see
|
cx |
(optional) character matrix; a formatted version of |
iN0 |
(optional) integer vector, specifying the location of the
non-zeroes of |
col.names, note.dropping.colnames
|
see |
dn |
|
a character matrix like cx, where the zeros have been replaced
with (padded versions of) zero.print.
As this is a dense matrix, do not use these functions for
really large (really) sparse matrices!
Martin Maechler
formatSpMatrix which calls formatSparseM() and is
the format method for sparse matrices.printSpMatrix which is used by the (typically
implicitly called) show and print methods
for sparse matrices.
m <- suppressWarnings(matrix(c(0, 3.2, 0,0, 11,0,0,0,0,-7,0), 4,9)) fm <- formatSparseM(m) noquote(fm) ## nice, but this is nicer {with "units" vertically aligned}: print(fm, quote=FALSE, right=TRUE) ## and "the same" as : Matrix(m) ## align = "right" is cheaper --> the "." are not aligned: noquote(f2 <- formatSparseM(m,align="r")) stopifnot(f2 == fm | m == 0, dim(f2) == dim(m), (f2 == ".") == (m == 0))m <- suppressWarnings(matrix(c(0, 3.2, 0,0, 11,0,0,0,0,-7,0), 4,9)) fm <- formatSparseM(m) noquote(fm) ## nice, but this is nicer {with "units" vertically aligned}: print(fm, quote=FALSE, right=TRUE) ## and "the same" as : Matrix(m) ## align = "right" is cheaper --> the "." are not aligned: noquote(f2 <- formatSparseM(m,align="r")) stopifnot(f2 == fm | m == 0, dim(f2) == dim(m), (f2 == ".") == (m == 0))
generalMatrix is a virtual subclass of
Matrix representing general (unstructured,
possibly nonsquare) matrices. Nonvirtual subclasses of
generalMatrix impose no constraints on the entries of the
represented matrix beyond the constraint imposed by the data type.
Dim, Dimnames
inherited from virtual superclass
Matrix.
factorsa list of
MatrixFactorization objects caching
factorizations of the represented matrix. It is updated
“automagically” by methods for generic functions that
compute matrix factorizations, such as lu.
The caching mechanism is not idiomatic as it circumvents R's
usual copy semantics; it may be deprecated in a future version of
Matrix, hence code intended to be forwards compatible will
not access the factors slot.
The direct, nonvirtual subclasses of generalMatrix defined in
package Matrix are listed below with links to virtual
superclasses defining their data type and storage format.
| Nonvirtual subclass | Data type | Storage format |
ngeMatrix |
nMatrix |
unpackedMatrix
|
lgeMatrix |
lMatrix |
unpackedMatrix
|
igeMatrix |
iMatrix |
unpackedMatrix
|
dgeMatrix |
dMatrix |
unpackedMatrix
|
zgeMatrix |
zMatrix |
unpackedMatrix
|
ngCMatrix |
nMatrix |
CsparseMatrix
|
lgCMatrix |
lMatrix |
CsparseMatrix
|
igCMatrix |
iMatrix |
CsparseMatrix
|
dgCMatrix |
dMatrix |
CsparseMatrix
|
zgCMatrix |
zMatrix |
CsparseMatrix
|
ngRMatrix |
nMatrix |
RsparseMatrix
|
lgRMatrix |
lMatrix |
RsparseMatrix
|
igRMatrix |
iMatrix |
RsparseMatrix
|
dgRMatrix |
dMatrix |
RsparseMatrix
|
zgRMatrix |
zMatrix |
RsparseMatrix
|
ngTMatrix |
nMatrix |
TsparseMatrix
|
lgTMatrix |
lMatrix |
TsparseMatrix
|
igTMatrix |
iMatrix |
TsparseMatrix
|
dgTMatrix |
dMatrix |
TsparseMatrix
|
zgTMatrix |
zMatrix |
TsparseMatrix
|
The subclasses of iMatrix and zMatrix were not defined
until Matrix version 1.8-0.
Related classes
symmetricMatrix,
posdefMatrix,
triangularMatrix,
diagonalMatrix, and
indexMatrix representing
Hermitian or symmetric, positive semidefinite, triangular, diagonal,
and index matrices. Generic functions Schur,
lu, and qr for Schur,
LU, and QR factorization of general matrices.
TODO.
head(x, ...) ## S4 method for signature 'Matrix' head(x, n = 6L, ...) ## S4 method for signature 'sparseVector' head(x, n = 6L, ...) tail(x, ...) ## S4 method for signature 'Matrix' tail(x, n = 6L, ...) ## S4 method for signature 'sparseVector' tail(x, n = 6L, ...)head(x, ...) ## S4 method for signature 'Matrix' head(x, n = 6L, ...) ## S4 method for signature 'sparseVector' head(x, n = 6L, ...) tail(x, ...) ## S4 method for signature 'Matrix' tail(x, n = 6L, ...) ## S4 method for signature 'sparseVector' tail(x, n = 6L, ...)
x |
. |
n |
. |
... |
. |
Generate the n by n symmetric Hilbert matrix. Because
these matrices are ill-conditioned for moderate to large n,
they are often used for testing numerical linear algebra code.
Hilbert(n)Hilbert(n)
n |
a non-negative integer. |
the n by n symmetric Hilbert matrix as a
"dpoMatrix" object.
the class dpoMatrix
Hilbert(6)Hilbert(6)
Methods for function image in package
Matrix. An image of a matrix simply color codes all matrix
entries and draws the matrix using an
grid of (colored) rectangles.
The Matrix package image methods are based on
levelplot() from package lattice; hence
these methods return an “object” of class "trellis",
producing a graphic when (auto-) print()ed.
## S4 method for signature 'dgTMatrix' image(x, xlim = c(1, di[2]), ylim = c(di[1], 1), aspect = "iso", sub = sprintf("Dimensions: %d x %d", di[1], di[2]), xlab = "Column", ylab = "Row", cuts = 15, useRaster = FALSE, useAbs = NULL, colorkey = !useAbs, col.regions = NULL, lwd = NULL, border.col = NULL, ...)## S4 method for signature 'dgTMatrix' image(x, xlim = c(1, di[2]), ylim = c(di[1], 1), aspect = "iso", sub = sprintf("Dimensions: %d x %d", di[1], di[2]), xlab = "Column", ylab = "Row", cuts = 15, useRaster = FALSE, useAbs = NULL, colorkey = !useAbs, col.regions = NULL, lwd = NULL, border.col = NULL, ...)
x |
a Matrix object, i.e., fulfilling |
xlim, ylim
|
x- and y-axis limits; may be used to “zoom
into” matrix. Note that |
aspect |
aspect ratio specified as number (y/x) or string;
see |
sub, xlab, ylab
|
axis annotation with sensible defaults;
see |
cuts |
number of levels the range of matrix values would be divided into. |
useRaster |
logical indicating if raster graphics should be used
(instead of the tradition rectangle vector drawing). If true,
Note that using raster graphics may often be faster, but can be slower, depending on the matrix dimensions and the graphics device (dimensions). |
useAbs |
logical indicating if |
colorkey |
logical indicating if a color key aka ‘legend’
should be produced. Default is to draw one, unless |
col.regions |
vector of gradually varying colors; see
|
lwd |
(only used when |
border.col |
color for the border of each rectangle. |
... |
further arguments passed to methods and
|
as all lattice graphics functions, image(<Matrix>)
returns a "trellis" object, effectively the result of
levelplot().
All methods currently end up calling the method for the
dgTMatrix class.
Use showMethods(image) to list them all.
levelplot, and
print.trellis from package lattice.
showMethods(image) ## And if you want to see the method definitions: showMethods(image, includeDefs = TRUE, inherited = FALSE) data(CAex, package = "Matrix") image(CAex, main = "image(CAex)") -> imgC; imgC stopifnot(!is.null(leg <- imgC$legend), is.list(leg$right)) # failed for 2 days .. image(CAex, useAbs=TRUE, main = "image(CAex, useAbs=TRUE)") cCA <- Cholesky(crossprod(CAex), Imult = .01) ## See ?print.trellis --- place two image() plots side by side: print(image(cCA, main="Cholesky(crossprod(CAex), Imult = .01)"), split=c(x=1,y=1,nx=2, ny=1), more=TRUE) print(image(cCA, useAbs=TRUE), split=c(x=2,y=1,nx=2,ny=1)) data(USCounties, package = "Matrix") image(USCounties)# huge image(sign(USCounties))## just the pattern # how the result looks, may depend heavily on # the device, screen resolution, antialiasing etc # e.g. x11(type="Xlib") may show very differently than cairo-based ## Drawing borders around each rectangle; # again, viewing depends very much on the device: image(USCounties[1:400,1:200], lwd=.1) ## Using (xlim,ylim) has advantage : matrix dimension and (col/row) indices: image(USCounties, c(1,200), c(1,400), lwd=.1) image(USCounties, c(1,300), c(1,200), lwd=.5 ) image(USCounties, c(1,300), c(1,200), lwd=.01) ## These 3 are all equivalent : (I1 <- image(USCounties, c(1,100), c(1,100), useAbs=FALSE)) I2 <- image(USCounties, c(1,100), c(1,100), useAbs=FALSE, border.col=NA) I3 <- image(USCounties, c(1,100), c(1,100), useAbs=FALSE, lwd=2, border.col=NA) stopifnot(all.equal(I1, I2, check.environment=FALSE), all.equal(I2, I3, check.environment=FALSE)) ## using an opaque border color image(USCounties, c(1,100), c(1,100), useAbs=FALSE, lwd=3, border.col = adjustcolor("skyblue", 1/2)) if(interactive() || nzchar(Sys.getenv("R_MATRIX_CHECK_EXTRA"))) { ## Using raster graphics: For PDF this would give a 77 MB file, ## however, for such a large matrix, this is typically considerably ## *slower* (than vector graphics rectangles) in most cases : if(doPNG <- !dev.interactive()) png("image-USCounties-raster.png", width=3200, height=3200) image(USCounties, useRaster = TRUE) # should not suffer from anti-aliasing if(doPNG) dev.off() ## and now look at the *.png image in a viewer you can easily zoom in and out }#only if(doExtras)showMethods(image) ## And if you want to see the method definitions: showMethods(image, includeDefs = TRUE, inherited = FALSE) data(CAex, package = "Matrix") image(CAex, main = "image(CAex)") -> imgC; imgC stopifnot(!is.null(leg <- imgC$legend), is.list(leg$right)) # failed for 2 days .. image(CAex, useAbs=TRUE, main = "image(CAex, useAbs=TRUE)") cCA <- Cholesky(crossprod(CAex), Imult = .01) ## See ?print.trellis --- place two image() plots side by side: print(image(cCA, main="Cholesky(crossprod(CAex), Imult = .01)"), split=c(x=1,y=1,nx=2, ny=1), more=TRUE) print(image(cCA, useAbs=TRUE), split=c(x=2,y=1,nx=2,ny=1)) data(USCounties, package = "Matrix") image(USCounties)# huge image(sign(USCounties))## just the pattern # how the result looks, may depend heavily on # the device, screen resolution, antialiasing etc # e.g. x11(type="Xlib") may show very differently than cairo-based ## Drawing borders around each rectangle; # again, viewing depends very much on the device: image(USCounties[1:400,1:200], lwd=.1) ## Using (xlim,ylim) has advantage : matrix dimension and (col/row) indices: image(USCounties, c(1,200), c(1,400), lwd=.1) image(USCounties, c(1,300), c(1,200), lwd=.5 ) image(USCounties, c(1,300), c(1,200), lwd=.01) ## These 3 are all equivalent : (I1 <- image(USCounties, c(1,100), c(1,100), useAbs=FALSE)) I2 <- image(USCounties, c(1,100), c(1,100), useAbs=FALSE, border.col=NA) I3 <- image(USCounties, c(1,100), c(1,100), useAbs=FALSE, lwd=2, border.col=NA) stopifnot(all.equal(I1, I2, check.environment=FALSE), all.equal(I2, I3, check.environment=FALSE)) ## using an opaque border color image(USCounties, c(1,100), c(1,100), useAbs=FALSE, lwd=3, border.col = adjustcolor("skyblue", 1/2)) if(interactive() || nzchar(Sys.getenv("R_MATRIX_CHECK_EXTRA"))) { ## Using raster graphics: For PDF this would give a 77 MB file, ## however, for such a large matrix, this is typically considerably ## *slower* (than vector graphics rectangles) in most cases : if(doPNG <- !dev.interactive()) png("image-USCounties-raster.png", width=3200, height=3200) image(USCounties, useRaster = TRUE) # should not suffer from anti-aliasing if(doPNG) dev.off() ## and now look at the *.png image in a viewer you can easily zoom in and out }#only if(doExtras)
iMatrix is a virtual subclass of Matrix
representing integer matrices, whose data are stored using numeric
vectors of type "integer". idenseMatrix and
isparseMatrix are virtual subclasses of iMatrix
representing its intersections with denseMatrix
and sparseMatrix.
Dim, Dimnames
inherited from virtual superclass
Matrix.
xan integer vector storing matrix entries. Details such as which entries are stored vary by storage format.
The nonvirtual subclasses of iMatrix are listed below with
links to virtual superclasses defining their structure and storage
format.
| Nonvirtual subclass | Structure | Storage format |
igeMatrix |
generalMatrix |
unpackedMatrix
|
isyMatrix |
symmetricMatrix |
unpackedMatrix
|
itrMatrix |
triangularMatrix |
unpackedMatrix
|
ispMatrix |
symmetricMatrix |
packedMatrix
|
itpMatrix |
triangularMatrix |
packedMatrix
|
igCMatrix |
generalMatrix |
CsparseMatrix
|
isCMatrix |
symmetricMatrix |
CsparseMatrix
|
itCMatrix |
triangularMatrix |
CsparseMatrix
|
igRMatrix |
generalMatrix |
RsparseMatrix
|
isRMatrix |
symmetricMatrix |
RsparseMatrix
|
itRMatrix |
triangularMatrix |
RsparseMatrix
|
igTMatrix |
generalMatrix |
TsparseMatrix
|
isTMatrix |
symmetricMatrix |
TsparseMatrix
|
itTMatrix |
triangularMatrix |
TsparseMatrix
|
idiMatrix |
diagonalMatrix |
unnamed
|
Subclasses of iMatrix were not defined until Matrix
version 1.8-0.
“Sister” classes nMatrix,
lMatrix, dMatrix, and
zMatrix representing boolean, logical, double,
and complex matrices.
## TODO## TODO
Class index is a virtual class designating index vectors,
or “subscripts”, for (possibly named) vectors and arrays.
It is typically used in signatures of methods for the subscript
and subassignment operators, namely [ and [<-.
It is implemented as a union of the atomic vector classes
numeric, logical,
and character.
[, [-methods, and
[<–methods.
showClass("index")showClass("index")
indexMatrix is a virtual subclass of
Matrix representing generalized row or column
index matrices. A generalized row index matrix is a matrix with at
most one nonzero entry in each row. A generalized column index matrix
is a matrix with at most one nonzero entry in each column.
Multiplying a matrix on the left by a generalized row index matrix is equivalent to sampling rows with replacement and scaling the sampled rows. Multiplying a matrix on the right by a generalized column index matrix is equivalent to sampling columns with replacement and scaling the sampled columns.
Standard index matrices are generalized index matrices whose rows or
columns are all standard unit vectors. Permutation matrices are
standard index matrices whose rows and columns are all standard
unit vectors. These special cases are represented by nonvirtual
subclasses indMatrix and pMatrix, documented below.
Diagonal matrices are generalized index matrices which are square and
whose nonzero entries are situated on the main diagonal. This special
case is represented by virtual subclass
diagonalMatrix.
Dim, Dimnames
inherited from virtual superclass
Matrix.
All direct, nonvirtual subclasses of indexMatrix defined in
package Matrix have two additional slots:
marginan integer, either 1 or 2, indicating that the represented matrix is a generalized row (1) or column (2) index matrix.
perman integer vector of length Dim[margin]
with elements sampled with replacement from
seq_len(Dim[-margin]). The represented matrix is zero
except for entries at [i, perm[i]] (margin=1) or
[perm[j], j] (margin=2), which may be nonzero.
Currently, the only direct, nonvirtual subclass of indexMatrix
is indMatrix, which represents standard index matrices.
Objects have margin and perm slots, as described in
‘Slots’. The represented matrix is equal to 1 in positions
[i, perm[i]] (margin=1) or [perm[j], j]
(margin=2) and otherwise equal to 0. Thus, indMatrix
extends not only indexMatrix but also
nMatrix, the virtual class of boolean matrices,
and sparseMatrix, the virtual class of sparse
format matrices. It is extended by pMatrix, which represents
permutation matrices. Objects of class pMatrix have no
additional slots. However, to be valid, their perm slot must
be a permutation of seq_len(n) for n=Dim[1]=Dim[2].
Related classes
generalMatrix,
symmetricMatrix,
posdefMatrix,
triangularMatrix, and
diagonalMatrix representing
general (unstructured, possibly nonsquare), Hermitian or symmetric,
positive semidefinite, triangular, and diagonal matrices.
Function isPerm for testing if an integer vector is a
valid permutation vector. Function invertPerm for
computing the inverse of a permutation vector.
matmult-methods for matrix products involving
indexMatrix.
p1 <- as(c(2,3,1), "pMatrix") (sm1 <- as(rep(c(2,3,1), e=3), "indMatrix")) stopifnot(all(sm1 == p1[rep(1:3, each=3),])) ## row-indexing of a <pMatrix> turns it into an <indMatrix>: class(p1[rep(1:3, each=3),]) set.seed(12) # so we know '10' is in sample ## random index matrix for 30 observations and 10 unique values: (s10 <- as(sample(10, 30, replace=TRUE),"indMatrix")) ## Sample rows of a numeric matrix : (mm <- matrix(1:10, nrow=10, ncol=3)) s10 %*% mm set.seed(27) IM1 <- as(sample(1:20, 100, replace=TRUE), "indMatrix") IM2 <- as(sample(1:18, 100, replace=TRUE), "indMatrix") (c12 <- crossprod(IM1,IM2)) ## same as cross-tabulation of the two index vectors: stopifnot(all(c12 - unclass(table(IM1@perm, IM2@perm)) == 0)) # 3 observations, 4 implied values, first does not occur in sample: as(2:4, "indMatrix") # 3 observations, 5 values, first and last do not occur in sample: as(list(2:4, 5), "indMatrix") as(sm1, "nMatrix") s10[1:7, 1:4] # gives an "ngTMatrix" (most economic!) s10[1:4, ] # preserves "indMatrix"-class I1 <- as(c(5:1,6:4,7:3), "indMatrix") I2 <- as(7:1, "pMatrix") (I12 <- rbind(I1, I2)) stopifnot(is(I12, "indMatrix"), identical(I12, rbind(I1, I2)), colSums(I12) == c(2L,2:4,4:2)) (pm1 <- as(as.integer(c(2,3,1)), "pMatrix")) t(pm1) # is the same as solve(pm1) pm1 %*% t(pm1) # check that the transpose is the inverse stopifnot(all(diag(3) == as(pm1 %*% t(pm1), "matrix")), is.logical(as(pm1, "matrix"))) set.seed(11) ## random permutation matrix : (p10 <- as(sample(10),"pMatrix")) ## Permute rows / columns of a numeric matrix : (mm <- round(array(rnorm(3 * 3), c(3, 3)), 2)) mm %*% pm1 pm1 %*% mm try(as(as.integer(c(3,3,1)), "pMatrix"))# Error: not a permutation as(pm1, "TsparseMatrix") p10[1:7, 1:4] # gives an "ngTMatrix" (most economic!) ## row-indexing of a <pMatrix> keeps it as an <indMatrix>: p10[1:3, ]p1 <- as(c(2,3,1), "pMatrix") (sm1 <- as(rep(c(2,3,1), e=3), "indMatrix")) stopifnot(all(sm1 == p1[rep(1:3, each=3),])) ## row-indexing of a <pMatrix> turns it into an <indMatrix>: class(p1[rep(1:3, each=3),]) set.seed(12) # so we know '10' is in sample ## random index matrix for 30 observations and 10 unique values: (s10 <- as(sample(10, 30, replace=TRUE),"indMatrix")) ## Sample rows of a numeric matrix : (mm <- matrix(1:10, nrow=10, ncol=3)) s10 %*% mm set.seed(27) IM1 <- as(sample(1:20, 100, replace=TRUE), "indMatrix") IM2 <- as(sample(1:18, 100, replace=TRUE), "indMatrix") (c12 <- crossprod(IM1,IM2)) ## same as cross-tabulation of the two index vectors: stopifnot(all(c12 - unclass(table(IM1@perm, IM2@perm)) == 0)) # 3 observations, 4 implied values, first does not occur in sample: as(2:4, "indMatrix") # 3 observations, 5 values, first and last do not occur in sample: as(list(2:4, 5), "indMatrix") as(sm1, "nMatrix") s10[1:7, 1:4] # gives an "ngTMatrix" (most economic!) s10[1:4, ] # preserves "indMatrix"-class I1 <- as(c(5:1,6:4,7:3), "indMatrix") I2 <- as(7:1, "pMatrix") (I12 <- rbind(I1, I2)) stopifnot(is(I12, "indMatrix"), identical(I12, rbind(I1, I2)), colSums(I12) == c(2L,2:4,4:2)) (pm1 <- as(as.integer(c(2,3,1)), "pMatrix")) t(pm1) # is the same as solve(pm1) pm1 %*% t(pm1) # check that the transpose is the inverse stopifnot(all(diag(3) == as(pm1 %*% t(pm1), "matrix")), is.logical(as(pm1, "matrix"))) set.seed(11) ## random permutation matrix : (p10 <- as(sample(10),"pMatrix")) ## Permute rows / columns of a numeric matrix : (mm <- round(array(rnorm(3 * 3), c(3, 3)), 2)) mm %*% pm1 pm1 %*% mm try(as(as.integer(c(3,3,1)), "pMatrix"))# Error: not a permutation as(pm1, "TsparseMatrix") p10[1:7, 1:4] # gives an "ngTMatrix" (most economic!) ## row-indexing of a <pMatrix> keeps it as an <indMatrix>: p10[1:3, ]
TODO.
## S4 method for signature 'Matrix' initialize(.Object, ...) ## S4 method for signature 'MatrixFactorization' initialize(.Object, ...) ## S4 method for signature 'sparseVector' initialize(.Object, i, x, ...)## S4 method for signature 'Matrix' initialize(.Object, ...) ## S4 method for signature 'MatrixFactorization' initialize(.Object, ...) ## S4 method for signature 'sparseVector' initialize(.Object, i, x, ...)
.Object |
. |
i |
. |
x |
. |
... |
. |
invertPerm and signPerm compute the inverse and sign
of a length-n permutation vector. isPerm tests
if a length-n integer vector is a valid permutation vector.
asPerm coerces a length-m transposition vector to a
length-n permutation vector, where m <= n.
invertPerm(p, off = 1L, ioff = 1L) signPerm(p, off = 1L) isPerm(p, off = 1L) asPerm(pivot, off = 1L, ioff = 1L, n = length(pivot)) invPerm(p, zero.p = FALSE, zero.res = FALSE)invertPerm(p, off = 1L, ioff = 1L) signPerm(p, off = 1L) isPerm(p, off = 1L) asPerm(pivot, off = 1L, ioff = 1L, n = length(pivot)) invPerm(p, zero.p = FALSE, zero.res = FALSE)
p |
an integer vector of length |
pivot |
an integer vector of length |
off |
an integer offset, indicating that |
ioff |
an integer offset, indicating that the result
should be a permutation of |
n |
a integer greater than or equal to |
zero.p |
a logical. Equivalent to |
zero.res |
a logical. Equivalent to |
invertPerm(p, off, ioff=1) is equivalent to
order(p) or sort.list(p)
for all values of off. For the default value
off=1, it returns the value of p after
p[p] <- seq_along(p).
invPerm is a simple wrapper around invertPerm,
retained for backwards compatibility.
By default, i.e., with off=1 and ioff=1:
invertPerm(p) returns an integer vector of length
length(p) such that p[invertPerm(p)]
and invertPerm(p)[p] are both seq_along(p),
i.e., the identity permutation.
signPerm(p) returns 1 if p is an even permutation
and -1 otherwise (i.e., if p is odd).
isPerm(p) returns TRUE if p is a
permutation of seq_along(p) and FALSE otherwise.
asPerm(pivot) returns the result of transposing elements
i and pivot[i] of a permutation vector initialized
as seq_len(n), for i in seq_along(pivot).
Class pMatrix of permutation matrices.
p <- sample(10L) # a random permutation vector ip <- invertPerm(p) s <- signPerm(p) ## 'p' and 'ip' are indeed inverses: stopifnot(exprs = { isPerm(p) isPerm(ip) identical(s, 1L) || identical(s, -1L) identical(s, signPerm(ip)) identical(p[ip], 1:10) identical(ip[p], 1:10) identical(invertPerm(ip), p) }) ## Product of transpositions (1 2)(2 1)(4 3)(6 8)(10 1) = (3 4)(6 8)(1 10) pivot <- c(2L, 1L, 3L, 3L, 5L, 8L, 7L, 8L, 9L, 1L) q <- asPerm(pivot) stopifnot(exprs = { identical(q, c(10L, 2L, 4L, 3L, 5L, 8L, 7L, 6L, 9L, 1L)) identical(q[q], seq_len(10L)) # because the permutation is odd: signPerm(q) == -1L }) invPerm # a less general version of 'invertPerm'p <- sample(10L) # a random permutation vector ip <- invertPerm(p) s <- signPerm(p) ## 'p' and 'ip' are indeed inverses: stopifnot(exprs = { isPerm(p) isPerm(ip) identical(s, 1L) || identical(s, -1L) identical(s, signPerm(ip)) identical(p[ip], 1:10) identical(ip[p], 1:10) identical(invertPerm(ip), p) }) ## Product of transpositions (1 2)(2 1)(4 3)(6 8)(10 1) = (3 4)(6 8)(1 10) pivot <- c(2L, 1L, 3L, 3L, 5L, 8L, 7L, 8L, 9L, 1L) q <- asPerm(pivot) stopifnot(exprs = { identical(q, c(10L, 2L, 4L, 3L, 5L, 8L, 7L, 6L, 9L, 1L)) identical(q[q], seq_len(10L)) # because the permutation is odd: signPerm(q) == -1L }) invPerm # a less general version of 'invertPerm'
Methods for generic functions anyNA(),
is.na(), is.nan(),
is.infinite(), and is.finite(),
for objects inheriting from virtual class
Matrix or sparseVector.
## S4 method for signature 'denseMatrix' is.na(x) ## S4 method for signature 'CsparseMatrix' is.na(x) ## S4 method for signature 'RsparseMatrix' is.na(x) ## S4 method for signature 'TsparseMatrix' is.na(x) ## S4 method for signature 'diagonalMatrix' is.na(x) ## S4 method for signature 'indMatrix' is.na(x) ## S4 method for signature 'sparseVector' is.na(x) ## and likewise for anyNA, is.nan, is.infinite, is.finite## S4 method for signature 'denseMatrix' is.na(x) ## S4 method for signature 'CsparseMatrix' is.na(x) ## S4 method for signature 'RsparseMatrix' is.na(x) ## S4 method for signature 'TsparseMatrix' is.na(x) ## S4 method for signature 'diagonalMatrix' is.na(x) ## S4 method for signature 'indMatrix' is.na(x) ## S4 method for signature 'sparseVector' is.na(x) ## and likewise for anyNA, is.nan, is.infinite, is.finite
x |
an R object, here a sparse or dense matrix or vector. |
For is.*(), an nMatrix or
nsparseVector matching the dimensions
of x and specifying the positions in x of
(some subset of) NA, NaN,
Inf, and -Inf.
For anyNA(), TRUE if x contains NA
or NaN and FALSE otherwise.
(M <- Matrix(1:6, nrow = 4, ncol = 3, dimnames = list(letters[1:4], LETTERS[1:3]))) stopifnot(!anyNA(M), !any(is.na(M))) M[2:3, 2] <- NA (inM <- is.na(M)) stopifnot(anyNA(M), sum(inM) == 2) (A <- spMatrix(nrow = 10, ncol = 20, i = c(1, 3:8), j = c(2, 9, 6:10), x = 7 * (1:7))) stopifnot(!anyNA(A), !any(is.na(A))) A[2, 3] <- A[1, 2] <- A[5, 5:9] <- NA (inA <- is.na(A)) stopifnot(anyNA(A), sum(inA) == 1 + 1 + 5)(M <- Matrix(1:6, nrow = 4, ncol = 3, dimnames = list(letters[1:4], LETTERS[1:3]))) stopifnot(!anyNA(M), !any(is.na(M))) M[2:3, 2] <- NA (inM <- is.na(M)) stopifnot(anyNA(M), sum(inM) == 2) (A <- spMatrix(nrow = 10, ncol = 20, i = c(1, 3:8), j = c(2, 9, 6:10), x = 7 * (1:7))) stopifnot(!anyNA(A), !any(is.na(A))) A[2, 3] <- A[1, 2] <- A[5, 5:9] <- NA (inA <- is.na(A)) stopifnot(anyNA(A), sum(inA) == 1 + 1 + 5)
dn NULL-like ?Are the dimnames dn NULL-like?
is.null.DN(dn) is less strict than is.null(dn),
because it is also true (TRUE) when the dimnames
dn are “like” NULL, or list(NULL,NULL), as
they can easily be for the traditional R matrices
(matrix) which have no formal class
definition, and hence much freedom in how their dimnames
look like.
is.null.DN(dn)is.null.DN(dn)
dn |
This function is really to be used on “traditional” matrices
rather than those inheriting from Matrix, as
the latter will always have dimnames list(NULL,NULL) exactly,
in such a case.
Martin Maechler
m1 <- m2 <- m3 <- m4 <- m <- matrix(round(100 * rnorm(6)), 2, 3) dimnames(m1) <- list(NULL, NULL) dimnames(m2) <- list(NULL, character()) dimnames(m3) <- rev(dimnames(m2)) dimnames(m4) <- rep(list(character()),2) m4 # prints absolutely identically to m c.o <- capture.output cm <- c.o(m) stopifnot(exprs = { m == m1; m == m2; m == m3; m == m4 identical(cm, c.o(m1)); identical(cm, c.o(m2)) identical(cm, c.o(m3)); identical(cm, c.o(m4)) }) hasNoDimnames <- function(.) is.null.DN(dimnames(.)) stopifnot(exprs = { hasNoDimnames(m) hasNoDimnames(m1); hasNoDimnames(m2) hasNoDimnames(m3); hasNoDimnames(m4) hasNoDimnames(Matrix(m) -> M) hasNoDimnames(as(M, "sparseMatrix")) })m1 <- m2 <- m3 <- m4 <- m <- matrix(round(100 * rnorm(6)), 2, 3) dimnames(m1) <- list(NULL, NULL) dimnames(m2) <- list(NULL, character()) dimnames(m3) <- rev(dimnames(m2)) dimnames(m4) <- rep(list(character()),2) m4 # prints absolutely identically to m c.o <- capture.output cm <- c.o(m) stopifnot(exprs = { m == m1; m == m2; m == m3; m == m4 identical(cm, c.o(m1)); identical(cm, c.o(m2)) identical(cm, c.o(m3)); identical(cm, c.o(m4)) }) hasNoDimnames <- function(.) is.null.DN(dimnames(.)) stopifnot(exprs = { hasNoDimnames(m) hasNoDimnames(m1); hasNoDimnames(m2) hasNoDimnames(m3); hasNoDimnames(m4) hasNoDimnames(Matrix(m) -> M) hasNoDimnames(as(M, "sparseMatrix")) })
Where the representation of an abstract object by an R object is not unique (because some details are unspecified by the class and unreferenced by methods), test for a “canonical” representation.
isCanonical(object, ...)isCanonical(object, ...)
object |
an R object. |
... |
optional arguments passed to methods. |
What is meant by “canonical” is up to the method writer. In
particular, a canonical representation need not be unique. In other
words, canonicalize(x) and canonicalize(y) need not be
identical for all sufficiently similar x and y of a
given class.
TRUE if x is canonical and FALSE otherwise.
## NA->TRUE for nonzero pattern dense ("ndenseMatrix") m1 <- m1. <- new("ngeMatrix", Dim = c(2L, 2L), x = c(FALSE, NA, TRUE, NA)) m1@x <- c(FALSE, TRUE, TRUE, TRUE) m1; m1. # same class, same matrix, different representations ## transpose for symmetric, conjugate transpose for Hermitian m2 <- m2. <- new("zsyMatrix", Dim = c(2L, 2L), uplo = "U", trans = "C", x = c(1+1i, 2+2i, 4+4i, 8+8i)) m2@x <- c(1+0i, 4-4i, 4+4i, 8+0i) m2; m2. ## zero for triangular, setting diagonal if diag="U" m3 <- m3. <- new("dtrMatrix", Dim = c(2L, 2L), uplo = "L", diag = "U", x = c(1, 2, 4, 8)) m3@x <- c(1, 2, 0, 1) m3; m3. ## integer-valued (and where possible integer-typed) slots ## for sparse vectors v1 <- v1. <- new("nsparseVector", length = 4.2, i = c(2.1, 4.5)) v1@length <- 4L; v1@i <- c(2L, 4L) v1; v1. ## similarly im <- .Machine[["integer.max"]] v2 <- v2. <- new("nsparseVector", length = im + 1.5, i = im + 0.5) v2@length <- im + 1; v2@i <- im ## v2; v2. # don't print such long vectors nms <- paste0(rep(c("m", "v"), c(5L, 2L)), c(1:3, 1:2)) obj <- mget(nms, inherits = FALSE) obj. <- mget(paste0(nms, "."), inherits = FALSE) stopifnot( all(vapply(obj , isCanonical, NA)), !any(vapply(obj., isCanonical, NA)))## NA->TRUE for nonzero pattern dense ("ndenseMatrix") m1 <- m1. <- new("ngeMatrix", Dim = c(2L, 2L), x = c(FALSE, NA, TRUE, NA)) m1@x <- c(FALSE, TRUE, TRUE, TRUE) m1; m1. # same class, same matrix, different representations ## transpose for symmetric, conjugate transpose for Hermitian m2 <- m2. <- new("zsyMatrix", Dim = c(2L, 2L), uplo = "U", trans = "C", x = c(1+1i, 2+2i, 4+4i, 8+8i)) m2@x <- c(1+0i, 4-4i, 4+4i, 8+0i) m2; m2. ## zero for triangular, setting diagonal if diag="U" m3 <- m3. <- new("dtrMatrix", Dim = c(2L, 2L), uplo = "L", diag = "U", x = c(1, 2, 4, 8)) m3@x <- c(1, 2, 0, 1) m3; m3. ## integer-valued (and where possible integer-typed) slots ## for sparse vectors v1 <- v1. <- new("nsparseVector", length = 4.2, i = c(2.1, 4.5)) v1@length <- 4L; v1@i <- c(2L, 4L) v1; v1. ## similarly im <- .Machine[["integer.max"]] v2 <- v2. <- new("nsparseVector", length = im + 1.5, i = im + 0.5) v2@length <- im + 1; v2@i <- im ## v2; v2. # don't print such long vectors nms <- paste0(rep(c("m", "v"), c(5L, 2L)), c(1:3, 1:2)) obj <- mget(nms, inherits = FALSE) obj. <- mget(paste0(nms, "."), inherits = FALSE) stopifnot( all(vapply(obj , isCanonical, NA)), !any(vapply(obj., isCanonical, NA)))
isDiagonal tests whether its argument
is a diagonal matrix. Unlike the analogous
isSymmetric, it is generically
from Matrix rather than base. Hence Matrix
defines methods for traditional matrices of implicit class
"matrix" or explicit class "table"
in addition to matrices inheriting from
virtual class "Matrix".
By our definition, diagonal matrices are square, i.e., they have the same number of rows and columns.
isDiagonal(object, ...)isDiagonal(object, ...)
object |
an R object, typically a matrix. |
... |
optional arguments passed from or to other methods. |
A logical, either TRUE or FALSE
(never NA).
isSymmetric;
virtual class "diagonalMatrix" and subclasses.
isDiagonal(matrix(c(2,0,0,1), 2,2)) # TRUE Np <- rpois(100, 1) (tab <- table(Np, Np+1L)) isDiagonal(tab) # TRUE ## Look at implementations: showMethods("isDiagonal", includeDefs = TRUE)isDiagonal(matrix(c(2,0,0,1), 2,2)) # TRUE Np <- rpois(100, 1) (tab <- table(Np, Np+1L)) isDiagonal(tab) # TRUE ## Look at implementations: showMethods("isDiagonal", includeDefs = TRUE)
Tests whether its argument is a symmetric square matrix, by default
tolerating some numerical fuzz and requiring symmetric dimnames
in addition to symmetry in the mathematical sense.
A complex matrix Z, i.e., inheriting from zMatrix,
must be “Hermitian” for isSymmetric(Z) to be true.
isSymmetric is a generic function in base, which has a
method for traditional matrices of implicit class
matrix. Documented here are methods in package Matrix
for subclasses of virtual class Matrix.
## S4 method for signature 'denseMatrix' isSymmetric(object, tol = 100 * .Machine$double.eps, tol1 = 8 * tol, trans = "C", checkDN = TRUE, ...) ## S4 method for signature 'CsparseMatrix' isSymmetric(object, tol = 100 * .Machine$double.eps, trans = "C", checkDN = TRUE, ...) ## S4 method for signature 'RsparseMatrix' isSymmetric(object, tol = 100 * .Machine$double.eps, trans = "C", checkDN = TRUE, ...) ## S4 method for signature 'TsparseMatrix' isSymmetric(object, tol = 100 * .Machine$double.eps, trans = "C", checkDN = TRUE, ...) ## S4 method for signature 'diagonalMatrix' isSymmetric(object, tol = 100 * .Machine$double.eps, trans = "C", checkDN = TRUE, ...) ## S4 method for signature 'indMatrix' isSymmetric(object, checkDN = TRUE, ...)## S4 method for signature 'denseMatrix' isSymmetric(object, tol = 100 * .Machine$double.eps, tol1 = 8 * tol, trans = "C", checkDN = TRUE, ...) ## S4 method for signature 'CsparseMatrix' isSymmetric(object, tol = 100 * .Machine$double.eps, trans = "C", checkDN = TRUE, ...) ## S4 method for signature 'RsparseMatrix' isSymmetric(object, tol = 100 * .Machine$double.eps, trans = "C", checkDN = TRUE, ...) ## S4 method for signature 'TsparseMatrix' isSymmetric(object, tol = 100 * .Machine$double.eps, trans = "C", checkDN = TRUE, ...) ## S4 method for signature 'diagonalMatrix' isSymmetric(object, tol = 100 * .Machine$double.eps, trans = "C", checkDN = TRUE, ...) ## S4 method for signature 'indMatrix' isSymmetric(object, checkDN = TRUE, ...)
object |
a |
tol, tol1
|
see |
trans |
a character string, |
checkDN |
a logical indicating whether symmetry of the
|
... |
further arguments passed from or to other methods.
Notably, for numeric or complex (but not integer, logical,
or pattern) |
The Dimnames slot of object, say dn,
is considered to be symmetric if and only if
dn[[1]] and dn[[2]] are identical or
one is NULL; and
ndn <- names(dn) is NULL or
ndn[1] and ndn[2] are identical or
one is the empty string "".
Hence list(a=nms, a=nms) is considered to be symmetric
and so too are list(a=nms, NULL) and list(NULL, a=nms).
Note that this definition is looser than that employed by
isSymmetric.matrix, which requires dn[1] and
dn[2] to be identical, where dn is the dimnames
attribute of a traditional matrix.
A logical, either TRUE or FALSE (never NA).
forceSymmetric, symmpart, skewpart;
virtual class symmetricMatrix and its subclasses.
isSymmetric(Diagonal(4)) # TRUE of course M <- Matrix(c(1,2,2,1), 2,2) isSymmetric(M) # TRUE (*and* of formal class "dsyMatrix") isSymmetric(as(M, "generalMatrix")) # still symmetric, even if not "formally" isSymmetric(triu(M)) # FALSE ## Look at implementations: showMethods("isSymmetric", includeDefs = TRUE) # includes S3 generic from baseisSymmetric(Diagonal(4)) # TRUE of course M <- Matrix(c(1,2,2,1), 2,2) isSymmetric(M) # TRUE (*and* of formal class "dsyMatrix") isSymmetric(as(M, "generalMatrix")) # still symmetric, even if not "formally" isSymmetric(triu(M)) # FALSE ## Look at implementations: showMethods("isSymmetric", includeDefs = TRUE) # includes S3 generic from base
isTriangular tests whether its argument
is a triangular matrix. Unlike the analogous
isSymmetric, it is generically
from Matrix rather than base. Hence Matrix
defines methods for traditional matrices of implicit class
"matrix" in addition to matrices inheriting from
virtual class "Matrix".
By our definition, triangular matrices are square, i.e., they have the same number of rows and columns.
isTriangular(object, upper = NA, ...)isTriangular(object, upper = NA, ...)
object |
an R object, typically a matrix. |
upper |
a logical, either |
... |
optional arguments passed from or to other methods. |
A logical, either TRUE or FALSE
(never NA).
If object is triangular and upper is NA, then
isTriangular returns TRUE with an attribute
kind, either "U" or "L", indicating that
object is upper or lower triangular, respectively.
Users should not rely on how kind is determined for diagonal
matrices, which are both upper and lower triangular.
isSymmetric;
virtual class "triangularMatrix" and subclasses.
isTriangular(Diagonal(4)) ## is TRUE: a diagonal matrix is also (both upper and lower) triangular (M <- Matrix(c(1,2,0,1), 2,2)) isTriangular(M) # TRUE (*and* of formal class "dtrMatrix") isTriangular(as(M, "generalMatrix")) # still triangular, even if not "formally" isTriangular(crossprod(M)) # FALSE ## Look at implementations: showMethods("isTriangular", includeDefs = TRUE)isTriangular(Diagonal(4)) ## is TRUE: a diagonal matrix is also (both upper and lower) triangular (M <- Matrix(c(1,2,0,1), 2,2)) isTriangular(M) # TRUE (*and* of formal class "dtrMatrix") isTriangular(as(M, "generalMatrix")) # still triangular, even if not "formally" isTriangular(crossprod(M)) # FALSE ## Look at implementations: showMethods("isTriangular", includeDefs = TRUE)
Computes Khatri-Rao products for any kind of matrices.
The Khatri-Rao product is a column-wise Kronecker product. Originally introduced by Khatri and Rao (1968), it has many different applications, see Liu and Trenkler (2008) for a survey. Notably, it is used in higher-dimensional tensor decompositions, see Bader and Kolda (2008).
KhatriRao(X, Y = X, FUN = "*", sparseY = TRUE, make.dimnames = FALSE)KhatriRao(X, Y = X, FUN = "*", sparseY = TRUE, make.dimnames = FALSE)
X, Y
|
matrices of with the same number of columns. |
FUN |
the (name of the) |
sparseY |
logical specifying if |
make.dimnames |
logical indicating if the result should inherit
|
a "CsparseMatrix", say R, the Khatri-Rao
product of X () and Y (), is of dimension ,
where the j-th column, R[,j] is the kronecker product
kronecker(X[,j], Y[,j]).
The current implementation is efficient for large sparse matrices.
Original by Michael Cysouw, Univ. Marburg; minor tweaks, bug fixes etc, by Martin Maechler.
Khatri, C. G., and Rao, C. Radhakrishna (1968) Solutions to Some Functional Equations and Their Applications to Characterization of Probability Distributions. Sankhya: Indian J. Statistics, Series A 30, 167–180.
Bader, Brett W, and Tamara G Kolda (2008) Efficient MATLAB Computations with Sparse and Factored Tensors. SIAM J. Scientific Computing 30, 205–231.
## Example with very small matrices: m <- matrix(1:12,3,4) d <- diag(1:4) KhatriRao(m,d) KhatriRao(d,m) dimnames(m) <- list(LETTERS[1:3], letters[1:4]) KhatriRao(m,d, make.dimnames=TRUE) KhatriRao(d,m, make.dimnames=TRUE) dimnames(d) <- list(NULL, paste0("D", 1:4)) KhatriRao(m,d, make.dimnames=TRUE) KhatriRao(d,m, make.dimnames=TRUE) dimnames(d) <- list(paste0("d", 10*1:4), paste0("D", 1:4)) (Kmd <- KhatriRao(m,d, make.dimnames=TRUE)) (Kdm <- KhatriRao(d,m, make.dimnames=TRUE)) nm <- as(m, "nsparseMatrix") nd <- as(d, "nsparseMatrix") KhatriRao(nm,nd, make.dimnames=TRUE) KhatriRao(nd,nm, make.dimnames=TRUE) stopifnot(dim(KhatriRao(m,d)) == c(nrow(m)*nrow(d), ncol(d))) ## border cases / checks: zm <- nm; zm[] <- FALSE # all FALSE matrix stopifnot(all(K1 <- KhatriRao(nd, zm) == 0), identical(dim(K1), c(12L, 4L)), all(K2 <- KhatriRao(zm, nd) == 0), identical(dim(K2), c(12L, 4L))) d0 <- d; d0[] <- 0; m0 <- Matrix(d0[-1,]) stopifnot(all(K3 <- KhatriRao(d0, m) == 0), identical(dim(K3), dim(Kdm)), all(K4 <- KhatriRao(m, d0) == 0), identical(dim(K4), dim(Kmd)), all(KhatriRao(d0, d0) == 0), all(KhatriRao(m0, d0) == 0), all(KhatriRao(d0, m0) == 0), all(KhatriRao(m0, m0) == 0), identical(dimnames(KhatriRao(m, d0, make.dimnames=TRUE)), dimnames(Kmd))) ## a matrix with "structural" and non-structural zeros: m01 <- new("dgCMatrix", i = c(0L, 2L, 0L, 1L), p = c(0L, 0L, 0L, 2L, 4L), Dim = 3:4, x = c(1, 0, 1, 0)) D4 <- Diagonal(4, x=1:4) # "as" d DU <- Diagonal(4)# unit-diagonal: uplo="U" (K5 <- KhatriRao( d, m01)) K5d <- KhatriRao( d, m01, sparseY=FALSE) K5Dd <- KhatriRao(D4, m01, sparseY=FALSE) K5Ud <- KhatriRao(DU, m01, sparseY=FALSE) (K6 <- KhatriRao(diag(3), t(m01))) K6D <- KhatriRao(Diagonal(3), t(m01)) K6d <- KhatriRao(diag(3), t(m01), sparseY=FALSE) K6Dd <- KhatriRao(Diagonal(3), t(m01), sparseY=FALSE) stopifnot(exprs = { all(K5 == K5d) identical(cbind(c(7L, 10L), c(3L, 4L)), which(K5 != 0, arr.ind = TRUE, useNames=FALSE)) identical(K5d, K5Dd) identical(K6, K6D) all(K6 == K6d) identical(cbind(3:4, 1L), which(K6 != 0, arr.ind = TRUE, useNames=FALSE)) identical(K6d, K6Dd) })## Example with very small matrices: m <- matrix(1:12,3,4) d <- diag(1:4) KhatriRao(m,d) KhatriRao(d,m) dimnames(m) <- list(LETTERS[1:3], letters[1:4]) KhatriRao(m,d, make.dimnames=TRUE) KhatriRao(d,m, make.dimnames=TRUE) dimnames(d) <- list(NULL, paste0("D", 1:4)) KhatriRao(m,d, make.dimnames=TRUE) KhatriRao(d,m, make.dimnames=TRUE) dimnames(d) <- list(paste0("d", 10*1:4), paste0("D", 1:4)) (Kmd <- KhatriRao(m,d, make.dimnames=TRUE)) (Kdm <- KhatriRao(d,m, make.dimnames=TRUE)) nm <- as(m, "nsparseMatrix") nd <- as(d, "nsparseMatrix") KhatriRao(nm,nd, make.dimnames=TRUE) KhatriRao(nd,nm, make.dimnames=TRUE) stopifnot(dim(KhatriRao(m,d)) == c(nrow(m)*nrow(d), ncol(d))) ## border cases / checks: zm <- nm; zm[] <- FALSE # all FALSE matrix stopifnot(all(K1 <- KhatriRao(nd, zm) == 0), identical(dim(K1), c(12L, 4L)), all(K2 <- KhatriRao(zm, nd) == 0), identical(dim(K2), c(12L, 4L))) d0 <- d; d0[] <- 0; m0 <- Matrix(d0[-1,]) stopifnot(all(K3 <- KhatriRao(d0, m) == 0), identical(dim(K3), dim(Kdm)), all(K4 <- KhatriRao(m, d0) == 0), identical(dim(K4), dim(Kmd)), all(KhatriRao(d0, d0) == 0), all(KhatriRao(m0, d0) == 0), all(KhatriRao(d0, m0) == 0), all(KhatriRao(m0, m0) == 0), identical(dimnames(KhatriRao(m, d0, make.dimnames=TRUE)), dimnames(Kmd))) ## a matrix with "structural" and non-structural zeros: m01 <- new("dgCMatrix", i = c(0L, 2L, 0L, 1L), p = c(0L, 0L, 0L, 2L, 4L), Dim = 3:4, x = c(1, 0, 1, 0)) D4 <- Diagonal(4, x=1:4) # "as" d DU <- Diagonal(4)# unit-diagonal: uplo="U" (K5 <- KhatriRao( d, m01)) K5d <- KhatriRao( d, m01, sparseY=FALSE) K5Dd <- KhatriRao(D4, m01, sparseY=FALSE) K5Ud <- KhatriRao(DU, m01, sparseY=FALSE) (K6 <- KhatriRao(diag(3), t(m01))) K6D <- KhatriRao(Diagonal(3), t(m01)) K6d <- KhatriRao(diag(3), t(m01), sparseY=FALSE) K6Dd <- KhatriRao(Diagonal(3), t(m01), sparseY=FALSE) stopifnot(exprs = { all(K5 == K5d) identical(cbind(c(7L, 10L), c(3L, 4L)), which(K5 != 0, arr.ind = TRUE, useNames=FALSE)) identical(K5d, K5Dd) identical(K6, K6D) all(K6 == K6d) identical(cbind(3:4, 1L), which(K6 != 0, arr.ind = TRUE, useNames=FALSE)) identical(K6d, K6Dd) })
A model matrix mm and corresponding response vector y
used in an example by Koenker and Ng. The matrix mm is a sparse
matrix with 1850 rows and 712 columns but only 8758 non-zero entries.
It is a "dgCMatrix" object. The vector y is just
numeric of length 1850.
data(KNex)data(KNex)
Roger Koenker and Pin Ng (2003). SparseM: A sparse matrix package for R; J. of Statistical Software, 8 (6), doi:10.18637/jss.v008.i06
data(KNex, package = "Matrix") class(KNex$mm) dim(KNex$mm) image(KNex$mm) str(KNex) system.time( # a fraction of a second sparse.sol <- with(KNex, solve(crossprod(mm), crossprod(mm, y)))) head(round(sparse.sol,3)) ## Compare with QR-based solution ("more accurate, but slightly slower"): system.time( sp.sol2 <- with(KNex, qr.coef(qr(mm), y) )) all.equal(as.vector(sparse.sol), sp.sol2, tolerance = 1e-13) # TRUEdata(KNex, package = "Matrix") class(KNex$mm) dim(KNex$mm) image(KNex$mm) str(KNex) system.time( # a fraction of a second sparse.sol <- with(KNex, solve(crossprod(mm), crossprod(mm, y)))) head(round(sparse.sol,3)) ## Compare with QR-based solution ("more accurate, but slightly slower"): system.time( sp.sol2 <- with(KNex, qr.coef(qr(mm), y) )) all.equal(as.vector(sparse.sol), sp.sol2, tolerance = 1e-13) # TRUE
Computes Kronecker products for objects inheriting from
"Matrix".
In order to preserver sparseness, we treat 0 * NA as 0,
not as NA as usually in R (and as used for the
base function kronecker).
signature(X = "Matrix", Y = "ANY") .......
signature(X = "ANY", Y = "Matrix") .......
signature(X = "diagonalMatrix", Y = "ANY") .......
signature(X = "sparseMatrix", Y = "ANY") .......
signature(X = "TsparseMatrix", Y = "TsparseMatrix") .......
signature(X = "dgTMatrix", Y = "dgTMatrix") .......
signature(X = "dtTMatrix", Y = "dtTMatrix") .......
signature(X = "indMatrix", Y = "indMatrix") .......
(t1 <- spMatrix(5,4, x= c(3,2,-7,11), i= 1:4, j=4:1)) # 5 x 4 (t2 <- kronecker(Diagonal(3, 2:4), t1)) # 15 x 12 ## should also work with special-cased logical matrices l3 <- upper.tri(matrix(,3,3)) M <- Matrix(l3) (N <- as(M, "nsparseMatrix")) # "ntCMatrix" (upper triangular) N2 <- as(N, "generalMatrix") # (lost "t"riangularity) MM <- kronecker(M,M) NN <- kronecker(N,N) # "dtTMatrix" i.e. did keep NN2 <- kronecker(N2,N2) stopifnot(identical(NN,MM), is(NN2, "sparseMatrix"), all(NN2 == NN), is(NN, "triangularMatrix"))(t1 <- spMatrix(5,4, x= c(3,2,-7,11), i= 1:4, j=4:1)) # 5 x 4 (t2 <- kronecker(Diagonal(3, 2:4), t1)) # 15 x 12 ## should also work with special-cased logical matrices l3 <- upper.tri(matrix(,3,3)) M <- Matrix(l3) (N <- as(M, "nsparseMatrix")) # "ntCMatrix" (upper triangular) N2 <- as(N, "generalMatrix") # (lost "t"riangularity) MM <- kronecker(M,M) NN <- kronecker(N,N) # "dtTMatrix" i.e. did keep NN2 <- kronecker(N2,N2) stopifnot(identical(NN,MM), is(NN2, "sparseMatrix"), all(NN2 == NN), is(NN, "triangularMatrix"))
lMatrix is a virtual subclass of Matrix
representing logical matrices, whose entries are
FALSE, TRUE, or NA. ldenseMatrix and
lsparseMatrix are virtual subclasses of lMatrix
representing its intersections with denseMatrix
and sparseMatrix.
lMatrix objects tend to arise as the return value of
op(A), where A is a Matrix object and op
is a function that preserves matrix dimensions and returns
FALSE, TRUE, or NA by element
(e.g., op(A) := A == 0 or !A or A | B for some
conformable B).
Dim, Dimnames
inherited from virtual superclass
Matrix.
xa logical vector storing matrix entries. Details such as which entries are stored vary by storage format.
The nonvirtual subclasses of lMatrix are listed below with
links to virtual superclasses defining their structure and storage
format.
| Nonvirtual subclass | Structure | Storage format |
lgeMatrix |
generalMatrix |
unpackedMatrix
|
lsyMatrix |
symmetricMatrix |
unpackedMatrix
|
ltrMatrix |
triangularMatrix |
unpackedMatrix
|
lspMatrix |
symmetricMatrix |
packedMatrix
|
ltpMatrix |
triangularMatrix |
packedMatrix
|
lgCMatrix |
generalMatrix |
CsparseMatrix
|
lsCMatrix |
symmetricMatrix |
CsparseMatrix
|
ltCMatrix |
triangularMatrix |
CsparseMatrix
|
lgRMatrix |
generalMatrix |
RsparseMatrix
|
lsRMatrix |
symmetricMatrix |
RsparseMatrix
|
ltRMatrix |
triangularMatrix |
RsparseMatrix
|
lgTMatrix |
generalMatrix |
TsparseMatrix
|
lsTMatrix |
symmetricMatrix |
TsparseMatrix
|
ltTMatrix |
triangularMatrix |
TsparseMatrix
|
ldiMatrix |
diagonalMatrix |
unnamed
|
“Sister” classes nMatrix,
iMatrix, dMatrix, and
zMatrix representing boolean, integer, double,
and complex matrices.
showClass("ldenseMatrix") as(diag(3) > 0, "ldenseMatrix") (m <- Matrix(c(0,0,2:0), 3,5, dimnames=list(LETTERS[1:3],NULL))) (lm <- (m > 1)) # lgC !lm # no longer sparse stopifnot(is(lm,"lsparseMatrix"), identical(!lm, m <= 1)) data(KNex, package = "Matrix") str(mmG.1 <- (KNex $ mm) > 0.1)# "lgC..." table(mmG.1@x)# however with many ``non-structural zeros'' ## from logical to nz_pattern -- okay when there are no NA's : nmG.1 <- as(mmG.1, "nMatrix") # <<< has "TRUE" also where mmG.1 had FALSE ## from logical to "double" dmG.1 <- as(mmG.1, "dMatrix") # has '0' and back: lmG.1 <- as(dmG.1, "lMatrix") stopifnot(identical(nmG.1, as((KNex $ mm) != 0,"nMatrix")), validObject(lmG.1), identical(lmG.1, mmG.1)) class(xnx <- crossprod(nmG.1))# "nsC.." class(xlx <- crossprod(mmG.1))# "dsC.." : numeric is0 <- (xlx == 0) mean(as.vector(is0))# 99.3% zeros: quite sparse, but table(xlx@x == 0)# more than half of the entries are (non-structural!) 0 stopifnot(isSymmetric(xlx), isSymmetric(xnx), ## compare xnx and xlx : have the *same* non-structural 0s : sapply(slotNames(xnx), function(n) identical(slot(xnx, n), slot(xlx, n))))showClass("ldenseMatrix") as(diag(3) > 0, "ldenseMatrix") (m <- Matrix(c(0,0,2:0), 3,5, dimnames=list(LETTERS[1:3],NULL))) (lm <- (m > 1)) # lgC !lm # no longer sparse stopifnot(is(lm,"lsparseMatrix"), identical(!lm, m <= 1)) data(KNex, package = "Matrix") str(mmG.1 <- (KNex $ mm) > 0.1)# "lgC..." table(mmG.1@x)# however with many ``non-structural zeros'' ## from logical to nz_pattern -- okay when there are no NA's : nmG.1 <- as(mmG.1, "nMatrix") # <<< has "TRUE" also where mmG.1 had FALSE ## from logical to "double" dmG.1 <- as(mmG.1, "dMatrix") # has '0' and back: lmG.1 <- as(dmG.1, "lMatrix") stopifnot(identical(nmG.1, as((KNex $ mm) != 0,"nMatrix")), validObject(lmG.1), identical(lmG.1, mmG.1)) class(xnx <- crossprod(nmG.1))# "nsC.." class(xlx <- crossprod(mmG.1))# "dsC.." : numeric is0 <- (xlx == 0) mean(as.vector(is0))# 99.3% zeros: quite sparse, but table(xlx@x == 0)# more than half of the entries are (non-structural!) 0 stopifnot(isSymmetric(xlx), isSymmetric(xnx), ## compare xnx and xlx : have the *same* non-structural 0s : sapply(slotNames(xnx), function(n) identical(slot(xnx, n), slot(xlx, n))))
Computes the pivoted LU factorization of an
real matrix , which has the general form
or (equivalently)
where
is an permutation matrix,
is an permutation matrix,
is an
unit lower trapezoidal matrix, and
is a
upper trapezoidal matrix.
Methods for denseMatrix are built on
LAPACK routine dgetrf, which does not permute columns,
so that is an identity matrix.
Methods for sparseMatrix are built on
CXSparse routine cs_lu, which requires ,
so that and are triangular matrices.
lu(x, ...) ## S4 method for signature 'denseMatrix' lu(x, warnSing = TRUE, direct = FALSE, ...) ## S4 method for signature 'CsparseMatrix' lu(x, errSing = TRUE, order = NA_integer_, tol = 1, direct = FALSE, ...) ## S4 method for signature 'matrix' lu(x, ...)lu(x, ...) ## S4 method for signature 'denseMatrix' lu(x, warnSing = TRUE, direct = FALSE, ...) ## S4 method for signature 'CsparseMatrix' lu(x, errSing = TRUE, order = NA_integer_, tol = 1, direct = FALSE, ...) ## S4 method for signature 'matrix' lu(x, ...)
x |
a finite matrix or
|
warnSing |
a logical indicating if a warning should
be signaled for singular |
errSing |
a logical indicating if an error should
be signaled for singular |
order |
an integer in |
tol |
a number. The original pivot element is used
if its absolute value exceeds |
direct |
a logical indicating if the result should be
constructed “directly” where |
... |
further arguments passed to or from methods. |
What happens when x is determined to be near-singular
differs by method. The method for class dgeMatrix
completes the factorization, warning if warnSing = TRUE
and in any case returning a valid denseLU
object. Users of this method can detect singular x with
a suitable warning handler; see tryCatch.
In contrast, the method for class dgCMatrix
abandons further computation, throwing an error if errSing = TRUE
and otherwise returning NA. Users of this method can
detect singular x with an error handler or by setting
errSing = FALSE and testing for a formal result with
is(., "sparseLU").
An object representing the factorization, inheriting from
virtual class LU. The specific class
is denseLU unless x inherits
from virtual class sparseMatrix,
in which case it is sparseLU.
The LAPACK source code, including documentation; see https://netlib.org/lapack/double/dgetrf.f.
Davis, T. A. (2006). Direct methods for sparse linear systems. Society for Industrial and Applied Mathematics. doi:10.1137/1.9780898718881
Golub, G. H., & Van Loan, C. F. (2013). Matrix computations (4th ed.). Johns Hopkins University Press. doi:10.56021/9781421407944
Classes denseLU and
sparseLU and their methods.
Classes dgeMatrix and
dgCMatrix.
Generic functions expand1 and expand2,
for constructing matrix factors from the result.
Generic functions Cholesky, BunchKaufman,
Schur, and qr,
for computing other factorizations.
showMethods("lu", inherited = FALSE) set.seed(0) ## ---- Dense ---------------------------------------------------------- (A1 <- Matrix(rnorm(9L), 3L, 3L)) (lu.A1 <- lu(A1)) (A2 <- round(10 * A1[, -3L])) (lu.A2 <- lu(A2)) ## A ~ P1' L U in floating point str(e.lu.A2 <- expand2(lu.A2), max.level = 2L) stopifnot(all.equal(A2, Reduce(`%*%`, e.lu.A2))) ## ---- Sparse --------------------------------------------------------- A3 <- as(readMM(system.file("external/pores_1.mtx", package = "Matrix")), "CsparseMatrix") (lu.A3 <- lu(A3)) ## A ~ P1' L U P2' in floating point str(e.lu.A3 <- expand2(lu.A3), max.level = 2L) stopifnot(all.equal(A3, Reduce(`%*%`, e.lu.A3)))showMethods("lu", inherited = FALSE) set.seed(0) ## ---- Dense ---------------------------------------------------------- (A1 <- Matrix(rnorm(9L), 3L, 3L)) (lu.A1 <- lu(A1)) (A2 <- round(10 * A1[, -3L])) (lu.A2 <- lu(A2)) ## A ~ P1' L U in floating point str(e.lu.A2 <- expand2(lu.A2), max.level = 2L) stopifnot(all.equal(A2, Reduce(`%*%`, e.lu.A2))) ## ---- Sparse --------------------------------------------------------- A3 <- as(readMM(system.file("external/pores_1.mtx", package = "Matrix")), "CsparseMatrix") (lu.A3 <- lu(A3)) ## A ~ P1' L U P2' in floating point str(e.lu.A3 <- expand2(lu.A3), max.level = 2L) stopifnot(all.equal(A3, Reduce(`%*%`, e.lu.A3)))
From an R object coercible to "TsparseMatrix",
typically a (sparse) matrix, produce its triplet representation which may
collapse to a “Duplet” in the case of binary aka pattern, such as
"nMatrix" objects.
mat2triplet(x, uniqT = FALSE)mat2triplet(x, uniqT = FALSE)
x |
any R object for which |
uniqT |
|
A list, typically with three components,
i |
vector of row indices for all non-zero entries of |
i |
vector of columns indices for all non-zero entries of |
x |
vector of all non-zero entries of |
Note that the order of the entries is determined by the
coercion to "TsparseMatrix" and hence typically
with increasing j (and increasing i within ties of j).
The mat2triplet() utility was created to be a more efficient and
more predictable substitute for summary(<sparseMatrix>).
UseRs have wrongly expected the latter to return a data frame with
columns i and j which however is wrong for a
"diagonalMatrix".
The summary() method for "sparseMatrix",
summary,sparseMatrix-method.
mat2triplet() is conceptually the inverse function of
spMatrix and (one case of) sparseMatrix.
mat2triplet # simple definition i <- c(1,3:8); j <- c(2,9,6:10); x <- 7 * (1:7) (Ax <- sparseMatrix(i, j, x = x)) ## 8 x 10 "dgCMatrix" str(trA <- mat2triplet(Ax)) stopifnot(i == sort(trA$i), sort(j) == trA$j, x == sort(trA$x)) D <- Diagonal(x=4:2) summary(D) str(mat2triplet(D))mat2triplet # simple definition i <- c(1,3:8); j <- c(2,9,6:10); x <- 7 * (1:7) (Ax <- sparseMatrix(i, j, x = x)) ## 8 x 10 "dgCMatrix" str(trA <- mat2triplet(Ax)) stopifnot(i == sort(trA$i), sort(j) == trA$j, x == sort(trA$x)) D <- Diagonal(x=4:2) summary(D) str(mat2triplet(D))
TODO.
Math(x) ## log(x, \dots)Math(x) ## log(x, \dots)
x |
. |
TODO.
Math2(x, digits)Math2(x, digits)
x |
. |
digits |
. |
The basic matrix product, %*% is implemented for all our
Matrix and also for
sparseVector classes, fully analogously to R's
base matrix and vector objects.
The functions crossprod and tcrossprod are
matrix products or “cross products”, ideally implemented
efficiently without computing t(.)'s unnecessarily.
They also return symmetricMatrix classed
matrices when easily detectable, e.g., in crossprod(m), the one
argument case.
tcrossprod() takes the cross-product of the transpose of a matrix.
tcrossprod(x) is formally equivalent to, but faster than, the
call x %*% t(x), and so is tcrossprod(x, y) instead of
x %*% t(y).
Boolean matrix products are computed via either
%&% or boolArith = TRUE.
## S4 method for signature 'CsparseMatrix,diagonalMatrix' x %*% y ## S4 method for signature 'CsparseMatrix,diagonalMatrix' crossprod(x, y = NULL, trans = "T", boolArith = NA, ...) ## .... and for many more signatures ## S4 method for signature 'TsparseMatrix,missing' tcrossprod(x, y = NULL, trans = "T", boolArith = NA, ...) ## .... and for many more signatures## S4 method for signature 'CsparseMatrix,diagonalMatrix' x %*% y ## S4 method for signature 'CsparseMatrix,diagonalMatrix' crossprod(x, y = NULL, trans = "T", boolArith = NA, ...) ## .... and for many more signatures ## S4 method for signature 'TsparseMatrix,missing' tcrossprod(x, y = NULL, trans = "T", boolArith = NA, ...) ## .... and for many more signatures
x |
a matrix-like object |
y |
a matrix-like object, or for |
trans |
TODO. |
boolArith |
|
... |
potentially more arguments passed to and from methods. |
For some classes in the Matrix package, such as
dgCMatrix, it is much faster to calculate the
cross-product of the transpose directly instead of calculating the
transpose first and then its cross-product.
boolArith = TRUE for regular (“non cross”) matrix
products, %*% cannot be specified. Instead, we provide the
%&% operator for boolean matrix products.
A Matrix object, in the one argument case
of an appropriate symmetric matrix class, i.e., inheriting from
symmetricMatrix.
signature(x = "dgeMatrix", y = "dgeMatrix"):
Matrix multiplication; ditto for several other signature
combinations, see showMethods("%*%", class = "dgeMatrix").
signature(x = "dtrMatrix", y = "matrix") and other
signatures (use showMethods("%*%", class="dtrMatrix")):
matrix multiplication. Multiplication of (matching) triangular
matrices now should remain triangular (in the sense of class
triangularMatrix).
signature(x = "dgeMatrix", y = "dgeMatrix"):
ditto for several other signatures, use
showMethods("crossprod", class = "dgeMatrix"), matrix
crossproduct, an efficient version of t(x) %*% y.
signature(x = "CsparseMatrix", y = "missing")
returns t(x) %*% x as an dsCMatrix object.
signature(x = "TsparseMatrix", y = "missing")
returns t(x) %*% x as an dsCMatrix object.
signature(x = "dtrMatrix", y =
"matrix") and other signatures, see "%*%" above.
boolArith = TRUE, FALSE or NA has been newly
introduced for Matrix 1.2.0 (March 2015). Its implementation
has still not been tested extensively. Notably the behaviour for
sparse matrices with x slots containing extra zeros had not been
documented previously, see the %&% help page.
Currently, boolArith = TRUE is implemented via
CsparseMatrix coercions which may be quite
inefficient for dense matrices. Contributions for efficiency
improvements are welcome.
tcrossprod in R's base, and
crossprod and %*%.
Matrix package %&% for boolean matrix product
methods.
## A random sparse "incidence" matrix : m <- matrix(0, 400, 500) set.seed(12) m[runif(314, 0, length(m))] <- 1 mm <- as(m, "CsparseMatrix") object.size(m) / object.size(mm) # smaller by a factor of > 200 ## tcrossprod() is very fast: system.time(tCmm <- tcrossprod(mm))# 0 (PIII, 933 MHz) system.time(cm <- crossprod(t(m))) # 0.16 system.time(cm. <- tcrossprod(m)) # 0.02 stopifnot(cm == as(tCmm, "matrix")) ## show sparse sub matrix tCmm[1:16, 1:30]## A random sparse "incidence" matrix : m <- matrix(0, 400, 500) set.seed(12) m[runif(314, 0, length(m))] <- 1 mm <- as(m, "CsparseMatrix") object.size(m) / object.size(mm) # smaller by a factor of > 200 ## tcrossprod() is very fast: system.time(tCmm <- tcrossprod(mm))# 0 (PIII, 933 MHz) system.time(cm <- crossprod(t(m))) # 0.16 system.time(cm. <- tcrossprod(m)) # 0.02 stopifnot(cm == as(tCmm, "matrix")) ## show sparse sub matrix tCmm[1:16, 1:30]
Construct a Matrix of a class inheriting from Matrix,
i.e., a “Matrix-package Matrix object”, using a
syntax known from base R's matrix().
Matrix(data=NA, nrow=1, ncol=1, byrow=FALSE, dimnames=NULL, sparse = NULL, doDiag = TRUE, forceCheck = FALSE, int2dbl = !as.logical(getOption("Matrix.use_iMatrix", .MatrixEnv[["use_iMatrix"]])))Matrix(data=NA, nrow=1, ncol=1, byrow=FALSE, dimnames=NULL, sparse = NULL, doDiag = TRUE, forceCheck = FALSE, int2dbl = !as.logical(getOption("Matrix.use_iMatrix", .MatrixEnv[["use_iMatrix"]])))
data |
an optional “numeric-alike” data vector,
|
nrow, ncol
|
when |
byrow |
logical. If |
dimnames |
a |
sparse |
logical or |
doDiag |
logical indicating if a Otherwise, if |
forceCheck |
logical indicating if the checks for structure
should even happen when |
int2dbl |
optional |
If either of nrow or ncol is not given, an attempt is
made to infer it from the length of data and the other
parameter (analogously to how matrix() works).
Further, Matrix() makes efforts to keep logical
matrices logical, i.e., inheriting from class lMatrix,
and analogously for integer or complex data.
raw data is currently coerced to
integer and treated as such.
Matrix() also determines specially structured matrices such as symmetric,
triangular or diagonal ones. Note that a symmetric matrix also
needs symmetric dimnames, e.g., by specifying
dimnames = list(NULL,NULL), see the examples.
Most of the time, the function works via a traditional (full)
matrix. However, Matrix(0, nrow,ncol) directly
constructs an “empty” sparseMatrix, as does
Matrix(FALSE, *).
Although it is sometime possible to mix unclassed matrices (created
with matrix) with ones of class "Matrix", it is much
safer to always use carefully constructed ones of class
"Matrix".
Returns matrix of a class that inherits from "Matrix".
Only if data is not a matrix and does not already inherit
from class Matrix are the arguments
nrow, ncol and byrow made use of.
The classes Matrix,
symmetricMatrix,
triangularMatrix, and
diagonalMatrix; further,
matrix.
Special matrices can be constructed, e.g., via
sparseMatrix (sparse), bdiag
(block-diagonal), bandSparse (banded sparse), or
Diagonal.
Matrix(0, 3, 2) # 3 by 2 matrix of zeros -> sparse Matrix(0, 3, 2, sparse=FALSE)# -> 'dense' ## 4 cases - 3 different results : Matrix(0, 2, 2) # diagonal ! Matrix(0, 2, 2, sparse=FALSE)# (ditto) Matrix(0, 2, 2, doDiag=FALSE)# -> sparse symm. "dsCMatrix" Matrix(0, 2, 2, sparse=FALSE, doDiag=FALSE)# -> dense symm. "dsyMatrix" Matrix(1:6, 3, 2) # a 3 by 2 matrix (+ integer warning) Matrix(1:6 + 1, nrow=3) ## logical ones: Matrix(diag(4) > 0) # -> "ldiMatrix" with diag = "U" Matrix(diag(4) > 0, sparse=TRUE) # (ditto) Matrix(diag(4) >= 0) # -> "lsyMatrix" (of all 'TRUE') ## triangular l3 <- upper.tri(matrix(,3,3)) (M <- Matrix(l3)) # -> "ltCMatrix" Matrix(! l3) # -> "ltrMatrix" as(l3, "CsparseMatrix")# "lgCMatrix" Matrix(1:9, nrow=3, dimnames = list(c("a", "b", "c"), c("A", "B", "C"))) (I3 <- Matrix(diag(3)))# identity, i.e., unit "diagonalMatrix" str(I3) # note 'diag = "U"' and the empty 'x' slot (A <- cbind(a=c(2,1), b=1:2))# symmetric *apart* from dimnames Matrix(A) # hence 'dgeMatrix' (As <- Matrix(A, dimnames = list(NULL,NULL)))# -> symmetric forceSymmetric(A) # also symmetric, w/ symm. dimnames stopifnot(is(As, "symmetricMatrix"), is(Matrix(0, 3,3), "sparseMatrix"), is(Matrix(FALSE, 1,1), "sparseMatrix"))Matrix(0, 3, 2) # 3 by 2 matrix of zeros -> sparse Matrix(0, 3, 2, sparse=FALSE)# -> 'dense' ## 4 cases - 3 different results : Matrix(0, 2, 2) # diagonal ! Matrix(0, 2, 2, sparse=FALSE)# (ditto) Matrix(0, 2, 2, doDiag=FALSE)# -> sparse symm. "dsCMatrix" Matrix(0, 2, 2, sparse=FALSE, doDiag=FALSE)# -> dense symm. "dsyMatrix" Matrix(1:6, 3, 2) # a 3 by 2 matrix (+ integer warning) Matrix(1:6 + 1, nrow=3) ## logical ones: Matrix(diag(4) > 0) # -> "ldiMatrix" with diag = "U" Matrix(diag(4) > 0, sparse=TRUE) # (ditto) Matrix(diag(4) >= 0) # -> "lsyMatrix" (of all 'TRUE') ## triangular l3 <- upper.tri(matrix(,3,3)) (M <- Matrix(l3)) # -> "ltCMatrix" Matrix(! l3) # -> "ltrMatrix" as(l3, "CsparseMatrix")# "lgCMatrix" Matrix(1:9, nrow=3, dimnames = list(c("a", "b", "c"), c("A", "B", "C"))) (I3 <- Matrix(diag(3)))# identity, i.e., unit "diagonalMatrix" str(I3) # note 'diag = "U"' and the empty 'x' slot (A <- cbind(a=c(2,1), b=1:2))# symmetric *apart* from dimnames Matrix(A) # hence 'dgeMatrix' (As <- Matrix(A, dimnames = list(NULL,NULL)))# -> symmetric forceSymmetric(A) # also symmetric, w/ symm. dimnames stopifnot(is(As, "symmetricMatrix"), is(Matrix(0, 3,3), "sparseMatrix"), is(Matrix(FALSE, 1,1), "sparseMatrix"))
Matrix is a virtual class representing matrices. All classes
of matrix defined in package Matrix are extensions of
Matrix. Nonvirtual class matrix defined
in package methods, from which traditional matrices inherit
implicitly, does not extend Matrix, but methods
are defined so that Matrix objects and matrix objects
are interoperable.
Diman integer vector of length 2 giving the
dimensions of the matrix. It is typically accessed using
dim; see dim-methods.
Dimnamesa list of length 2. Each element must be
NULL or a character vector of length equal to the
corresponding element of Dim. It is typically accessed
using dimnames; see dimnames-methods.
Objects inheriting from virtual class Matrix can be categorized
in three ways: by data type, by structure, and by storage format.
Accordingly, it can be helpful to think of nonvirtual subclasses of
Matrix as triples
(<data type>, <structure>, <storage format>)
and to think of virtual subclasses of Matrix as sets of triples
satisfying constraints.
The data type of a Matrix object refers to the set of possible
values of entries in the represented matrix. Package Matrix
supports five data types: boolean (or “nonzero pattern”),
logical, integer, double, and complex. How boolean data are stored
varies by format, whereas logical, integer, double, and complex data
are always stored in atomic vectors of the corresponding type.
Virtual classes nMatrix,
lMatrix, iMatrix,
dMatrix, and zMatrix
designate Matrix objects whose data type is one of the
supported five (n=nonzero pattern, l=logical, i=integer, d=double,
z=complex, following the LAPACK naming scheme).
The structure of a Matrix object refers to the mathematical
properties of the represented matrix. Virtual classes
generalMatrix,
symmetricMatrix,
triangularMatrix,
diagonalMatrix, and
indexMatrix represent general (not having any
specific properties), Hermitian or symmetric, triangular, diagonal,
and index matrices. posdefMatrix is a virtual
subclass of symmetricMatrix representing positive semidefinite
matrices.
The storage format of a Matrix object describes the relation
between what is stored in memory and entries in the represented
matrix. A matrix can be represented in multiple formats, some more
efficient than others depending on, e.g., the sparsity of the matrix
and the order in which entries are accessed in computation. Virtual
class sparseMatrix designates Matrix
objects whose format is such that the space required to represent an
matrix with nonzero entries is
. Its “complement” is
virtual class denseMatrix.
CsparseMatrix,
RsparseMatrix, and
TsparseMatrix are virtual subclasses of
sparseMatrix corresponding to the compressed sparse column,
compressed sparse row, and triplet formats.
unpackedMatrix and
packedMatrix are virtual subclasses of
denseMatrix corresponding to the conventional and packed
formats defined by LAPACK, storing data of length and
and listing matrix entries in
column-major order: https://netlib.org/lapack/lug/node121.html
A canonical example of a nonvirtual subclass of Matrix is
dgCMatrix. Objects of this class have double
precision data, general structure, and compressed sparse column
format. Accordingly, dgCMatrix extends virtual classes
dMatrix, generalMatrix, and CsparseMatrix.
Indeed, nonvirtual subclasses of Matrix defined in package
Matrix tend to have names of the form
xyyMatrix, where the first character indicates the
data type and the second and third characters together indicate the
structure and format. This naming scheme is inspired by LAPACK:
https://netlib.org/lapack/lug/node24.html
S4 methods are defined for the S4 generic functions listed by
.S4methods(class = "Matrix").
S3 methods are defined for the S3 generic functions listed by
.S3methods(class = "Matrix"). They are defined so that
Matrix objects are handled correctly even in environments where
the S4 generic functions are not available, such as the evaluation
frame of a function from a package that does not import the S4 generic
function. Notably, the S3 method defined for as.matrix
ensures that base functions like apply,
eigen, and svd behave as documented even
if their first argument is a Matrix (rather than matrix)
object. Note that this mechanism is not needed for generic functions
that dispatch “internally”; see InternalGenerics.
Methods are documented by generic function rather than by class, hence see:
help.search(keyword = "methods", package = "Matrix")
help("<generic>-methods", package = "Matrix")
Methods defined in package Matrix for virtual class
Matrix or one of its virtual subclasses can be dispatched for
subclasses of Matrix defined in other packages. The behaviour
is undefined if the “foreign” subclass does not extend any
nonvirtual “local” subclass. Authors of packages that define
such foreign subclasses may need to override local methods with
methods of their own. An example is class MultiCompanion in
package mcompanion (version 0.6 at the time of writing).
Nonvirtual subclasses such as dgCMatrix and
dgeMatrix. Function Matrix, a
widely used (but not the only) constructor for Matrix objects.
cl <- getClass("Matrix") showClass(cl) # output with all slots, superclasses, subclasses subcl <- cl@subclasses subcl <- subcl[vapply(subcl, packageSlot, "") == "Matrix"] # exclude foreign ones (nms <- names(subcl)) stopifnot(all(endsWith(nms, "Matrix"))) # our convention iv <- vapply(nms, isVirtualClass, FALSE) ( v <- nms[ iv]) # virtual subclasses (nv <- nms[!iv]) # nonvirtual subclasses (nv.prefix <- sub("Matrix$", "", nv)) tabulate(nchar(nv.prefix), 6L) # 3-letter prefix, usually ...cl <- getClass("Matrix") showClass(cl) # output with all slots, superclasses, subclasses subcl <- cl@subclasses subcl <- subcl[vapply(subcl, packageSlot, "") == "Matrix"] # exclude foreign ones (nms <- names(subcl)) stopifnot(all(endsWith(nms, "Matrix"))) # our convention iv <- vapply(nms, isVirtualClass, FALSE) ( v <- nms[ iv]) # virtual subclasses (nv <- nms[!iv]) # nonvirtual subclasses (nv.prefix <- sub("Matrix$", "", nv)) tabulate(nchar(nv.prefix), 6L) # 3-letter prefix, usually ...
Return the (maybe super-)class of class cl from
package Matrix, returning character(0) if there is none.
MatrixClass(cl, cld = getClassDef(cl), ...Matrix = TRUE, dropVirtual = TRUE, ...)MatrixClass(cl, cld = getClassDef(cl), ...Matrix = TRUE, dropVirtual = TRUE, ...)
cl |
string, class name |
cld |
its class definition |
...Matrix |
|
dropVirtual |
|
... |
further arguments are passed to
|
a character string
Martin Maechler, 24 Mar 2009
Matrix, the mother of all Matrix classes.
mkA <- setClass("A", contains="dgCMatrix") (A <- mkA()) stopifnot(identical( MatrixClass("A"), "dgCMatrix"))mkA <- setClass("A", contains="dgCMatrix") (A <- mkA()) stopifnot(identical( MatrixClass("A"), "dgCMatrix"))
MatrixFactorization is the virtual class of
factorizations of matrices ,
having the general form
or (equivalently)
where and are permutation matrices.
Factorizations requiring symmetric have the constraint
, and factorizations without row
or column pivoting have the constraints
and ,
where and are the
and identity matrices.
CholeskyFactorization, BunchKaufmanFactorization,
SchurFactorization, LU, and QR are the virtual
subclasses of MatrixFactorization containing all Cholesky,
Bunch-Kaufman, Schur, LU, and QR factorizations, respectively.
Diman integer vector of length 2 giving the dimensions of the factorized matrix.
Dimnamesa list of length 2 preserving the
dimnames of the factorized matrix. Each element
must be NULL or a character vector of length equal
to the corresponding element of Dim.
determinantsignature(x = "MatrixFactorization", logarithm = "missing"):
sets logarithm = TRUE and recalls the generic function.
dimsignature(x = "MatrixFactorization"):
returns x@Dim.
dimnamessignature(x = "MatrixFactorization"):
returns x@Dimnames.
dimnames<-signature(x = "MatrixFactorization", value = "NULL"):
returns x with x@Dimnames set to list(NULL, NULL).
dimnames<-signature(x = "MatrixFactorization", value = "list"):
returns x with x@Dimnames set to value.
lengthsignature(x = "MatrixFactorization"):
returns prod(x@Dim).
showsignature(object = "MatrixFactorization"):
prints the internal representation of the factorization using
str.
solvesignature(a = "MatrixFactorization", b = .):
see solve-methods.
unnamesignature(obj = "MatrixFactorization"):
returns obj with obj@Dimnames set to
list(NULL, NULL).
Classes extending CholeskyFactorization, namely
Cholesky, pCholesky,
and CHMfactor.
Classes extending BunchKaufmanFactorization, namely
BunchKaufman and pBunchKaufman.
Classes extending SchurFactorization, namely
Schur.
Classes extending LU, namely
denseLU and sparseLU.
Classes extending QR, namely sparseQR.
Generic functions Cholesky, BunchKaufman,
Schur, lu, and qr for
computing factorizations.
Generic functions expand1 and expand2
for constructing matrix factors from MatrixFactorization
objects.
showClass("MatrixFactorization")showClass("MatrixFactorization")
Compute the nearest positive definite matrix to an approximate one, typically a correlation or variance-covariance matrix.
nearPD(x, corr = FALSE, keepDiag = FALSE, base.matrix = FALSE, do2eigen = TRUE, doSym = FALSE, doDykstra = TRUE, only.values = FALSE, ensureSymmetry = !isSymmetric(x), eig.tol = 1e-06, conv.tol = 1e-07, posd.tol = 1e-08, maxit = 100, conv.norm.type = "I", trace = FALSE)nearPD(x, corr = FALSE, keepDiag = FALSE, base.matrix = FALSE, do2eigen = TRUE, doSym = FALSE, doDykstra = TRUE, only.values = FALSE, ensureSymmetry = !isSymmetric(x), eig.tol = 1e-06, conv.tol = 1e-07, posd.tol = 1e-08, maxit = 100, conv.norm.type = "I", trace = FALSE)
x |
numeric |
corr |
logical indicating if the matrix should be a correlation matrix. |
keepDiag |
logical, generalizing |
base.matrix |
logical indicating if the resulting |
do2eigen |
logical indicating if a
|
doSym |
logical indicating if |
doDykstra |
logical indicating if Dykstra's correction should be
used; true by default. If false, the algorithm is basically the
direct fixpoint iteration
|
only.values |
logical; if |
ensureSymmetry |
logical; by default, |
eig.tol |
defines relative positiveness of eigenvalues compared
to largest one, |
conv.tol |
convergence tolerance for Higham algorithm. |
posd.tol |
tolerance for enforcing positive definiteness (in the
final |
maxit |
maximum number of iterations allowed. |
conv.norm.type |
convergence norm type ( |
trace |
logical or integer specifying if convergence monitoring should be traced. |
This implements the algorithm of Higham (2002), and then (if
do2eigen is true) forces positive definiteness using code from
posdefify. The algorithm of Knol and ten
Berge (1989) (not implemented here) is more general in that it
allows constraints to (1) fix some rows (and columns) of the matrix and
(2) force the smallest eigenvalue to have a certain value.
Note that setting corr = TRUE just sets diag(.) <- 1
within the algorithm.
Higham (2002) uses Dykstra's correction, but the version by Jens
Oehlschlägel did not use it (accidentally),
and still gave reasonable results; this simplification, now only
used if doDykstra = FALSE,
was active in nearPD() up to Matrix version 0.999375-40.
If only.values = TRUE, a numeric vector of eigenvalues of the
approximating matrix;
Otherwise, as by default, an S3 object of class
"nearPD", basically a list with components
mat |
a matrix of class |
eigenvalues |
numeric vector of eigenvalues of |
corr |
logical, just the argument |
normF |
the Frobenius norm ( |
iterations |
number of iterations needed. |
converged |
logical indicating if iterations converged. |
Jens Oehlschlägel donated a first version. Subsequent changes by the Matrix package authors.
Cheng, Sheung Hun and Higham, Nick (1998) A Modified Cholesky Algorithm Based on a Symmetric Indefinite Factorization; SIAM J. Matrix Anal.\ Appl., 19, 1097–1110.
Knol DL, ten Berge JMF (1989) Least-squares approximation of an improper correlation matrix by a proper one. Psychometrika 54, 53–61.
Higham, Nick (2002) Computing the nearest correlation matrix - a problem from finance; IMA Journal of Numerical Analysis 22, 329–343.
A first version of this (with non-optional corr=TRUE)
has been available as nearcor(); and
more simple versions with a similar purpose
posdefify(), both from package sfsmisc.
## Higham(2002), p.334f - simple example A <- matrix(1, 3,3); A[1,3] <- A[3,1] <- 0 n.A <- nearPD(A, corr=TRUE, do2eigen=FALSE) n.A[c("mat", "normF")] n.A.m <- nearPD(A, corr=TRUE, do2eigen=FALSE, base.matrix=TRUE)$mat stopifnot(exprs = { #=-------------- all.equal(n.A$mat[1,2], 0.760689917) all.equal(n.A$normF, 0.52779033, tolerance=1e-9) all.equal(n.A.m, unname(as.matrix(n.A$mat)), tolerance = 1e-15)# seen rel.d.= 1.46e-16 }) set.seed(27) m <- matrix(round(rnorm(25),2), 5, 5) m <- m + t(m) diag(m) <- pmax(0, diag(m)) + 1 (m <- round(cov2cor(m), 2)) str(near.m <- nearPD(m, trace = TRUE)) round(near.m$mat, 2) norm(m - near.m$mat) # 1.102 / 1.08 if(requireNamespace("sfsmisc")) { m2 <- sfsmisc::posdefify(m) # a simpler approach norm(m - m2) # 1.185, i.e., slightly "less near" } round(nearPD(m, only.values=TRUE), 9) ## A longer example, extended from Jens' original, ## showing the effects of some of the options: pr <- Matrix(c(1, 0.477, 0.644, 0.478, 0.651, 0.826, 0.477, 1, 0.516, 0.233, 0.682, 0.75, 0.644, 0.516, 1, 0.599, 0.581, 0.742, 0.478, 0.233, 0.599, 1, 0.741, 0.8, 0.651, 0.682, 0.581, 0.741, 1, 0.798, 0.826, 0.75, 0.742, 0.8, 0.798, 1), nrow = 6, ncol = 6) nc. <- nearPD(pr, conv.tol = 1e-7) # default nc.$iterations # 2 nc.1 <- nearPD(pr, conv.tol = 1e-7, corr = TRUE) nc.1$iterations # 11 / 12 (!) ncr <- nearPD(pr, conv.tol = 1e-15) str(ncr)# still 2 iterations ncr.1 <- nearPD(pr, conv.tol = 1e-15, corr = TRUE) ncr.1 $ iterations # 27 / 30 ! ncF <- nearPD(pr, conv.tol = 1e-15, conv.norm = "F") stopifnot(all.equal(ncr, ncF))# norm type does not matter at all in this example ## But indeed, the 'corr = TRUE' constraint did ensure a better solution; ## cov2cor() does not just fix it up equivalently : norm(pr - cov2cor(ncr$mat)) # = 0.09994 norm(pr - ncr.1$mat) # = 0.08746 / 0.08805 ### 3) a real data example from a 'systemfit' model (3 eq.): (load(system.file("external", "symW.rda", package="Matrix"))) # "symW" dim(symW) # 24 x 24 class(symW)# "dsCMatrix": sparse symmetric if(dev.interactive()) image(symW) EV <- eigen(symW, only=TRUE)$values summary(EV) ## looking more closely {EV sorted decreasingly}: tail(EV)# all 6 are negative EV2 <- eigen(sWpos <- nearPD(symW)$mat, only=TRUE)$values stopifnot(EV2 > 0) if(requireNamespace("sfsmisc")) { plot(pmax(1e-3,EV), EV2, type="o", log="xy", xaxt="n", yaxt="n") for(side in 1:2) sfsmisc::eaxis(side) } else plot(pmax(1e-3,EV), EV2, type="o", log="xy") abline(0, 1, col="red3", lty=2)## Higham(2002), p.334f - simple example A <- matrix(1, 3,3); A[1,3] <- A[3,1] <- 0 n.A <- nearPD(A, corr=TRUE, do2eigen=FALSE) n.A[c("mat", "normF")] n.A.m <- nearPD(A, corr=TRUE, do2eigen=FALSE, base.matrix=TRUE)$mat stopifnot(exprs = { #=-------------- all.equal(n.A$mat[1,2], 0.760689917) all.equal(n.A$normF, 0.52779033, tolerance=1e-9) all.equal(n.A.m, unname(as.matrix(n.A$mat)), tolerance = 1e-15)# seen rel.d.= 1.46e-16 }) set.seed(27) m <- matrix(round(rnorm(25),2), 5, 5) m <- m + t(m) diag(m) <- pmax(0, diag(m)) + 1 (m <- round(cov2cor(m), 2)) str(near.m <- nearPD(m, trace = TRUE)) round(near.m$mat, 2) norm(m - near.m$mat) # 1.102 / 1.08 if(requireNamespace("sfsmisc")) { m2 <- sfsmisc::posdefify(m) # a simpler approach norm(m - m2) # 1.185, i.e., slightly "less near" } round(nearPD(m, only.values=TRUE), 9) ## A longer example, extended from Jens' original, ## showing the effects of some of the options: pr <- Matrix(c(1, 0.477, 0.644, 0.478, 0.651, 0.826, 0.477, 1, 0.516, 0.233, 0.682, 0.75, 0.644, 0.516, 1, 0.599, 0.581, 0.742, 0.478, 0.233, 0.599, 1, 0.741, 0.8, 0.651, 0.682, 0.581, 0.741, 1, 0.798, 0.826, 0.75, 0.742, 0.8, 0.798, 1), nrow = 6, ncol = 6) nc. <- nearPD(pr, conv.tol = 1e-7) # default nc.$iterations # 2 nc.1 <- nearPD(pr, conv.tol = 1e-7, corr = TRUE) nc.1$iterations # 11 / 12 (!) ncr <- nearPD(pr, conv.tol = 1e-15) str(ncr)# still 2 iterations ncr.1 <- nearPD(pr, conv.tol = 1e-15, corr = TRUE) ncr.1 $ iterations # 27 / 30 ! ncF <- nearPD(pr, conv.tol = 1e-15, conv.norm = "F") stopifnot(all.equal(ncr, ncF))# norm type does not matter at all in this example ## But indeed, the 'corr = TRUE' constraint did ensure a better solution; ## cov2cor() does not just fix it up equivalently : norm(pr - cov2cor(ncr$mat)) # = 0.09994 norm(pr - ncr.1$mat) # = 0.08746 / 0.08805 ### 3) a real data example from a 'systemfit' model (3 eq.): (load(system.file("external", "symW.rda", package="Matrix"))) # "symW" dim(symW) # 24 x 24 class(symW)# "dsCMatrix": sparse symmetric if(dev.interactive()) image(symW) EV <- eigen(symW, only=TRUE)$values summary(EV) ## looking more closely {EV sorted decreasingly}: tail(EV)# all 6 are negative EV2 <- eigen(sWpos <- nearPD(symW)$mat, only=TRUE)$values stopifnot(EV2 > 0) if(requireNamespace("sfsmisc")) { plot(pmax(1e-3,EV), EV2, type="o", log="xy", xaxt="n", yaxt="n") for(side in 1:2) sfsmisc::eaxis(side) } else plot(pmax(1e-3,EV), EV2, type="o", log="xy") abline(0, 1, col="red3", lty=2)
nMatrix is a virtual subclass of Matrix
representing boolean (or “nonzero pattern”) matrices,
whose entries are FALSE or TRUE. ndenseMatrix
and nsparseMatrix are virtual subclasses of nMatrix
representing its intersections with denseMatrix
and sparseMatrix.
nMatrix objects tend to arise as the return value of
op(A), where A is a Matrix object and op
is a function that preserves matrix dimensions and returns
FALSE or TRUE by element
(e.g., op(A) := is.nan(A)).
Dim, Dimnames
inherited from virtual superclass
Matrix.
Certain nonvirtual subclasses of nMatrix defined in package
Matrix (see ‘Subclasses’) also have:
xa logical vector storing matrix entries.
Details such as which entries are stored vary by storage
format. NA elements are valid and mapped to TRUE,
hence methods often must operate on not x but rather
x | is.na(x).
The nonvirtual subclasses of nMatrix are listed below with
links to virtual superclasses defining their structure and storage
format. Marked (*) classes have an x slot storing
matrix entries. The details of the x slot vary by storage
format. Unmarked classes do not have an x slot. These use
sparse formats that store positions of nonzero entries instead of
entries themselves.
| Nonvirtual subclass | Structure | Storage format |
* ngeMatrix |
generalMatrix |
unpackedMatrix
|
* nsyMatrix |
symmetricMatrix |
unpackedMatrix
|
* ntrMatrix |
triangularMatrix |
unpackedMatrix
|
* nspMatrix |
symmetricMatrix |
packedMatrix
|
* ntpMatrix |
triangularMatrix |
packedMatrix
|
ngCMatrix |
generalMatrix |
CsparseMatrix
|
nsCMatrix |
symmetricMatrix |
CsparseMatrix
|
ntCMatrix |
triangularMatrix |
CsparseMatrix
|
ngRMatrix |
generalMatrix |
RsparseMatrix
|
nsRMatrix |
symmetricMatrix |
RsparseMatrix
|
ntRMatrix |
triangularMatrix |
RsparseMatrix
|
ngTMatrix |
generalMatrix |
TsparseMatrix
|
nsTMatrix |
symmetricMatrix |
TsparseMatrix
|
ntTMatrix |
triangularMatrix |
TsparseMatrix
|
* ndiMatrix |
diagonalMatrix |
unnamed
|
indMatrix |
indexMatrix |
unnamed
|
Class ndiMatrix was not defined until Matrix version
1.6-2.
“Sister” classes lMatrix,
iMatrix, dMatrix, and
zMatrix representing logical, integer, double,
and complex matrices.
getClass("nMatrix") L3 <- Matrix(upper.tri(diag(3))) L3 # an "ltCMatrix" as(L3, "nMatrix") # -> ntC* ## similar, not using Matrix() as(upper.tri(diag(3)), "nMatrix")# currently "ngTMatrix" showClass("ndenseMatrix") as(diag(3) > 0, "ndenseMatrix")# -> "nge" (m <- Matrix(c(0,0,2:0), 3,5, dimnames=list(LETTERS[1:3],NULL))) ## ``extract the nonzero-pattern of (m) into an nMatrix'': nm <- as(m, "nsparseMatrix") ## -> will be a "ngCMatrix" str(nm) # no 'x' slot nnm <- !nm # no longer sparse ## consistency check: stopifnot(xor(as( nm, "matrix"), as(nnm, "matrix"))) ## low-level way of adding "non-structural zeros" : nnm <- as(nnm, "lsparseMatrix") # "lgCMatrix" nnm@x[2:4] <- c(FALSE, NA, NA) nnm as(nnm, "nMatrix") # NAs *and* non-structural 0 |---> 'TRUE' data(KNex, package = "Matrix") nmm <- as(KNex $ mm, "nMatrix") str(xlx <- crossprod(nmm))# "nsCMatrix" stopifnot(isSymmetric(xlx)) image(xlx, main=paste("crossprod(nmm) : Sparse", class(xlx)))getClass("nMatrix") L3 <- Matrix(upper.tri(diag(3))) L3 # an "ltCMatrix" as(L3, "nMatrix") # -> ntC* ## similar, not using Matrix() as(upper.tri(diag(3)), "nMatrix")# currently "ngTMatrix" showClass("ndenseMatrix") as(diag(3) > 0, "ndenseMatrix")# -> "nge" (m <- Matrix(c(0,0,2:0), 3,5, dimnames=list(LETTERS[1:3],NULL))) ## ``extract the nonzero-pattern of (m) into an nMatrix'': nm <- as(m, "nsparseMatrix") ## -> will be a "ngCMatrix" str(nm) # no 'x' slot nnm <- !nm # no longer sparse ## consistency check: stopifnot(xor(as( nm, "matrix"), as(nnm, "matrix"))) ## low-level way of adding "non-structural zeros" : nnm <- as(nnm, "lsparseMatrix") # "lgCMatrix" nnm@x[2:4] <- c(FALSE, NA, NA) nnm as(nnm, "nMatrix") # NAs *and* non-structural 0 |---> 'TRUE' data(KNex, package = "Matrix") nmm <- as(KNex $ mm, "nMatrix") str(xlx <- crossprod(nmm))# "nsCMatrix" stopifnot(isSymmetric(xlx)) image(xlx, main=paste("crossprod(nmm) : Sparse", class(xlx)))
Returns the number of non-zero values of a numeric-like R object, and
in particular an object x inheriting from class
Matrix.
nnzero(x, ...) ## S4 method for signature 'denseMatrix' nnzero(x, na.counted = NA, ...) ## S4 method for signature 'sparseMatrix' nnzero(x, na.counted = NA, ...)nnzero(x, ...) ## S4 method for signature 'denseMatrix' nnzero(x, na.counted = NA, ...) ## S4 method for signature 'sparseMatrix' nnzero(x, na.counted = NA, ...)
x |
an R object, typically inheriting from class
|
na.counted |
a
For sparse matrices, you may often want to use |
... |
optional arguments passed from or to other methods. |
the number of non zero entries in x (typically
integer).
Note that for a symmetric sparse matrix S (i.e., inheriting from
class symmetricMatrix), nnzero(S) is
typically twice the length(S@x).
signature(x = "ANY")the default method for
non-Matrix class objects, simply counts the
number 0s in x, counting NA's depending on
the na.counted argument, see above.
signature(x = "denseMatrix")conceptually the same as
for traditional matrix objects, care has to be taken
for "symmetricMatrix" objects.
signature(x = "diagonalMatrix"), and
signature(x = "indMatrix")
fast simple methods for these
special "sparseMatrix" classes.
signature(x = "sparseMatrix")typically, the most
interesting method, also carefully taking
"symmetricMatrix" objects into account.
The Matrix class also has a
length method; typically, length(M) is much
larger than nnzero(M) for a sparse matrix M, and the latter is
a better indication of the size of M.
m <- Matrix(0+1:28, nrow = 4) m[-3,c(2,4:5,7)] <- m[ 3, 1:4] <- m[1:3, 6] <- 0 (mT <- as(m, "TsparseMatrix")) nnzero(mT) (S <- crossprod(mT)) nnzero(S) str(S) # slots are smaller than nnzero() stopifnot(nnzero(S) == sum(as.matrix(S) != 0))# failed earlier data(KNex, package = "Matrix") M <- KNex$mm class(M) dim(M) length(M); stopifnot(length(M) == prod(dim(M))) nnzero(M) # more relevant than length ## the above are also visible from str(M)m <- Matrix(0+1:28, nrow = 4) m[-3,c(2,4:5,7)] <- m[ 3, 1:4] <- m[1:3, 6] <- 0 (mT <- as(m, "TsparseMatrix")) nnzero(mT) (S <- crossprod(mT)) nnzero(S) str(S) # slots are smaller than nnzero() stopifnot(nnzero(S) == sum(as.matrix(S) != 0))# failed earlier data(KNex, package = "Matrix") M <- KNex$mm class(M) dim(M) length(M); stopifnot(length(M) == prod(dim(M))) nnzero(M) # more relevant than length ## the above are also visible from str(M)
Computes a matrix norm of x, using Lapack for dense matrices.
The norm can be the one ("O", or "1") norm, the
infinity ("I") norm, the Frobenius ("F") norm,
the maximum modulus ("M") among elements of a matrix, or the
spectral norm or 2-norm ("2"), as determined by the value of
type.
norm(x, type, ...)norm(x, type, ...)
x |
a real or complex matrix. |
type |
A character indicating the type of norm desired.
The default is |
... |
further arguments passed to or from other methods. |
For dense matrices, the methods eventually call the Lapack functions
dlange, dlansy, dlantr, zlange,
zlansy, and zlantr.
A numeric value of class "norm", representing the quantity
chosen according to type.
Anderson, E., et al. (1994). LAPACK User's Guide, 2nd edition, SIAM, Philadelphia.
onenormest(), an approximate randomized estimate
of the 1-norm condition number, efficient for large sparse matrices.
The norm() function from R's base package.
x <- Hilbert(9) norm(x)# = "O" = "1" stopifnot(identical(norm(x), norm(x, "1"))) norm(x, "I")# the same, because 'x' is symmetric allnorms <- function(x) { ## norm(NA, "2") did not work until R 4.0.0 do2 <- getRversion() >= "4.0.0" || !anyNA(x) vapply(c("1", "I", "F", "M", if(do2) "2"), norm, 0, x = x) } allnorms(x) allnorms(Hilbert(10)) i <- c(1,3:8); j <- c(2,9,6:10); x <- 7 * (1:7) A <- sparseMatrix(i, j, x = x) ## 8 x 10 "dgCMatrix" (sA <- sparseMatrix(i, j, x = x, symmetric = TRUE)) ## 10 x 10 "dsCMatrix" (tA <- sparseMatrix(i, j, x = x, triangular= TRUE)) ## 10 x 10 "dtCMatrix" (allnorms(A) -> nA) allnorms(sA) allnorms(tA) stopifnot(all.equal(nA, allnorms(as(A, "matrix"))), all.equal(nA, allnorms(tA))) # because tA == rbind(A, 0, 0) A. <- A; A.[1,3] <- NA stopifnot(is.na(allnorms(A.))) # gave errorx <- Hilbert(9) norm(x)# = "O" = "1" stopifnot(identical(norm(x), norm(x, "1"))) norm(x, "I")# the same, because 'x' is symmetric allnorms <- function(x) { ## norm(NA, "2") did not work until R 4.0.0 do2 <- getRversion() >= "4.0.0" || !anyNA(x) vapply(c("1", "I", "F", "M", if(do2) "2"), norm, 0, x = x) } allnorms(x) allnorms(Hilbert(10)) i <- c(1,3:8); j <- c(2,9,6:10); x <- 7 * (1:7) A <- sparseMatrix(i, j, x = x) ## 8 x 10 "dgCMatrix" (sA <- sparseMatrix(i, j, x = x, symmetric = TRUE)) ## 10 x 10 "dsCMatrix" (tA <- sparseMatrix(i, j, x = x, triangular= TRUE)) ## 10 x 10 "dtCMatrix" (allnorms(A) -> nA) allnorms(sA) allnorms(tA) stopifnot(all.equal(nA, allnorms(as(A, "matrix"))), all.equal(nA, allnorms(tA))) # because tA == rbind(A, 0, 0) A. <- A; A.[1,3] <- NA stopifnot(is.na(allnorms(A.))) # gave error
TODO.
## S4 method for signature 'ndenseMatrix' !x ## S4 method for signature 'nsparseMatrix' !x ## S4 method for signature 'ndiMatrix' !x ## S4 method for signature 'nsparseVector' !x ## S4 method for signature 'ldenseMatrix' !x ## S4 method for signature 'lsparseMatrix' !x ## S4 method for signature 'ldiMatrix' !x ## S4 method for signature 'lsparseVector' !x ## S4 method for signature 'Matrix' !x ## S4 method for signature 'sparseVector' !x## S4 method for signature 'ndenseMatrix' !x ## S4 method for signature 'nsparseMatrix' !x ## S4 method for signature 'ndiMatrix' !x ## S4 method for signature 'nsparseVector' !x ## S4 method for signature 'ldenseMatrix' !x ## S4 method for signature 'lsparseMatrix' !x ## S4 method for signature 'ldiMatrix' !x ## S4 method for signature 'lsparseVector' !x ## S4 method for signature 'Matrix' !x ## S4 method for signature 'sparseVector' !x
x |
. |
Many Matrix package (binary operator) methods for Matrix
objects (of super classes Matrix and
sparseVector) combined with (base)
matrix, and atomic vectors numeric, logical,
complex, etc.
Methods are both defined as group methods, e.g., for the "Arith"
group, and as regular methods for specific binary operators, e.g., +.
Ops(e1, e2) Arith(e1, e2) Compare(e1, e2) Logic(e1, e2) # e1 + e2 # e1 / e2 # e1 | e2 # etcOps(e1, e2) Arith(e1, e2) Compare(e1, e2) Logic(e1, e2) # e1 + e2 # e1 / e2 # e1 | e2 # etc
e1, e2
|
typically “numeric-alike” vectors,
|
typically a class "Matrix" object of a class
related to the classes of e1 and e2.
Package methods: The overview Methods;
further getGroup, getGroupMembers
## 'Ops': the union group of the 3 binary op groups: getGroupMembers("Ops") # "Arith" "Compare" "Logic" ## getGroupMembers("Arith") # "+" "-" "*" "^" "%%" "%/%" "/" getGroupMembers("Compare") # "==" ">" "<" "!=" "<=" ">=" getGroupMembers("Logic") # "&" "|" ( *not* containing unary "!" )## 'Ops': the union group of the 3 binary op groups: getGroupMembers("Ops") # "Arith" "Compare" "Logic" ## getGroupMembers("Arith") # "+" "-" "*" "^" "%%" "%/%" "/" getGroupMembers("Compare") # "==" ">" "<" "!=" "<=" ">=" getGroupMembers("Logic") # "&" "|" ( *not* containing unary "!" )
pack() coerces dense symmetric and dense triangular matrices
from unpacked format (storing the full matrix) to packed format
(storing only one of the upper and lower triangles). unpack()
performs the reverse coercion. The two formats are formalized
by the virtual classes "packedMatrix" and
"unpackedMatrix".
pack(x, ...) ## S4 method for signature 'unpackedMatrix' pack(x, symmetric = NA, upperTri = NA, ...) ## S4 method for signature 'matrix' pack(x, symmetric = NA, upperTri = NA, ...) unpack(x, ...)pack(x, ...) ## S4 method for signature 'unpackedMatrix' pack(x, symmetric = NA, upperTri = NA, ...) ## S4 method for signature 'matrix' pack(x, symmetric = NA, upperTri = NA, ...) unpack(x, ...)
x |
A dense symmetric or dense triangular matrix.
|
symmetric |
logical (including |
upperTri |
(for triangular |
... |
further arguments passed to or from other methods. |
pack(x) checks matrices x not inheriting from
one of the virtual classes "symmetricMatrix"
"triangularMatrix" for symmetry
(via isSymmetric())
then for upper and lower triangularity
(via isTriangular()) in order to identify a suitable
coercion. Setting one or both of symmetric and upperTri
to TRUE or FALSE rather than NA allows skipping
of irrelevant tests for large matrices known to be symmetric or
(upper or lower) triangular.
Users should not assume that pack() and unpack()
are inverse operations. Specifically, y <- unpack(pack(x))
may not reproduce an "unpackedMatrix" x in the sense of
identical(). See the examples.
pack():a "packedMatrix" giving
the condensed representation of x.
unpack():an "unpackedMatrix" giving
the full storage representation of x.
showMethods("pack") (s <- crossprod(matrix(sample(15), 5,3))) # traditional symmetric matrix (sp <- pack(s)) mt <- as.matrix(tt <- tril(s)) (pt <- pack(mt)) stopifnot(identical(pt, pack(tt)), dim(s ) == dim(sp), all(s == sp), dim(mt) == dim(pt), all(mt == pt), all(mt == tt)) showMethods("unpack") (cp4 <- chol(Hilbert(4))) # is triangular tp4 <- pack(cp4) # [t]riangular [p]acked str(tp4) (unpack(tp4)) stopifnot(identical(tp4, pack(unpack(tp4)))) z1 <- new("dsyMatrix", Dim = c(2L, 2L), x = as.double(1:4), uplo = "U") z2 <- unpack(pack(z1)) stopifnot(!identical(z1, z2), # _not_ identical all(z1 == z2)) # but mathematically equal cbind(z1@x, z2@x) # (unused!) lower triangle is "lost" in translationshowMethods("pack") (s <- crossprod(matrix(sample(15), 5,3))) # traditional symmetric matrix (sp <- pack(s)) mt <- as.matrix(tt <- tril(s)) (pt <- pack(mt)) stopifnot(identical(pt, pack(tt)), dim(s ) == dim(sp), all(s == sp), dim(mt) == dim(pt), all(mt == pt), all(mt == tt)) showMethods("unpack") (cp4 <- chol(Hilbert(4))) # is triangular tp4 <- pack(cp4) # [t]riangular [p]acked str(tp4) (unpack(tp4)) stopifnot(identical(tp4, pack(unpack(tp4)))) z1 <- new("dsyMatrix", Dim = c(2L, 2L), x = as.double(1:4), uplo = "U") z2 <- unpack(pack(z1)) stopifnot(!identical(z1, z2), # _not_ identical all(z1 == z2)) # but mathematically equal cbind(z1@x, z2@x) # (unused!) lower triangle is "lost" in translation
packedMatrix is a virtual subclass of
denseMatrix representing packed dense format
matrices, as defined by LAPACK:
https://netlib.org/lapack/lug/node121.html. To represent an
n-by-n symmetric, Hermitian, or triangular matrix
A, this format stores a vector of length
choose(n+1, 2) == n*(n+1)/2 (the number of entries in the upper
or lower triangle), of which n*(n+1)/2 or fewer elements are
actually used (fewer if there are additional formal constraints on the
structure of A).
Dim, Dimnames
inherited from virtual superclass
Matrix. Dim[1] and Dim[2] must
be equal.
uploa character string, either "U" or
"L". "U" indicates that x stores only the
upper triangular entries of A. "L" indicates that
x stores only the lower triangular entries of A.
xa vector of length n*(n+1)/2,
n=Dim[1]=Dim[2], storing upper or lower triangular
(depending on uplo) entries of A in column-major
order. Authors of subclasses of packedMatrix may declare
that only a subset k of the elements of x is used to
determine A, defining implicitly a function F such
that A = F(x[k]); see ‘Subclasses’ for examples in
package Matrix.
The nonvirtual subclasses of packedMatrix defined in package
Matrix are listed below with links to virtual superclasses
defining their data type and structure.
| Nonvirtual subclass | Data type | Structure |
nspMatrix |
nMatrix |
symmetricMatrix
|
lspMatrix |
lMatrix |
symmetricMatrix
|
ispMatrix |
iMatrix |
symmetricMatrix
|
dspMatrix |
dMatrix |
symmetricMatrix
|
zspMatrix |
zMatrix |
symmetricMatrix
|
dppMatrix |
dMatrix |
posdefMatrix
|
zppMatrix |
zMatrix |
posdefMatrix
|
ntpMatrix |
nMatrix |
triangularMatrix
|
ltpMatrix |
lMatrix |
triangularMatrix
|
itpMatrix |
iMatrix |
triangularMatrix
|
dtpMatrix |
dMatrix |
triangularMatrix
|
ztpMatrix |
zMatrix |
triangularMatrix
|
The subclasses of iMatrix and zMatrix were not defined
until Matrix version 1.8-0. The other subclasses predate
packedMatrix itself, which was not defined until Matrix
version 1.4-1; previously, those subclasses were direct extensions of
denseMatrix.
The mapping from the x slot of length n*(n+1)/2 to the
n-by-n represented matrix A is given by:
A[i, j]
| i < j | i = j | i > j
-------------------------------|----------------------------|-----------------------------|----------------------------
.spMatrix, uplo="U" | x[i+ j*(j-1)/2] | x[i+ j*(j-1)/2] | x[j+ i*(i-1)/2]
zspMatrix, uplo="U", trans="C" | x[i+ j*(j-1)/2] | Re(x[i+ j*(j-1)/2])+0i | Conj(x[j+ i*(i-1)/2])
.spMatrix, uplo="L" | x[j+(2*n-i)*(i-1)/2] | x[i+(2*n-j)*(j-1)/2] | x[i+(2*n-j)*(j-1)/2]
zspMatrix, uplo="L", trans="C" | Conj(x[j+(2*n-i)*(i-1)/2]) | Re(x[i+(2*n-j)*(j-1)/2])+0i | x[i+(2*n-j)*(j-1)/2]
.tpMatrix, uplo="U", diag="N" | x[i+ j*(j-1)/2] | x[i+ j*(j-1)/2] | 0
.tpMatrix, uplo="U", diag="U" | x[i+ j*(j-1)/2] | 1 | 0
.tpMatrix, uplo="L", diag="N" | 0 | x[i+(2*n-j)*(j-1)/2] | x[i+(2*n-j)*(j-1)/2]
.tpMatrix, uplo="L", diag="U" | 0 | 1 | x[i+(2*n-j)*(j-1)/2]
Classes .spMatrix represent Hermitian or symmetric A.
Objects have x and uplo slots. If uplo="U", then
x stores the n*(n+1)/2 upper triangular entries of
A. If uplo="L", then x stores the
n*(n+1)/2 lower triangular entries of A. Objects of
class zspMatrix have an additional trans slot that
distinguishes Hermitian and symmetric A, which use
trans="C" and "T", respectively. If trans="C",
then the imaginary parts of x[du] (uplo="U") or
x[dl] (uplo="L") are not referenced, where du=d,
dl=length(x)+1-d, and d=cumsum(seq_len(n)). (The
diagonal entries of Hermitian matrices are real by definition.)
Classes dppMatrix and zppMatrix extend dspMatrix
and zspMatrix and represent positive semidefinite A.
Positive semidefiniteness of A induces a constraint on the
x slot. However, this constraint is not strictly enforced by
the validity methods, which test only that the diagonal entries of
A are nonnegative (a necessary, not sufficient condition).
For zppMatrix, only trans="C" is valid. Class
copMatrix extends dppMatrix and represents correlation
matrices; it has an additional sd slot, a numeric vector of
length n listing standard deviations, enabling recovery of a
covariance matrix.
Classes .tpMatrix represent triangular A. Objects have
x, uplo, and diag slots. If uplo="U",
then A is upper triangular and x[-du] stores the
n*(n-1)/2 strictly upper triangular entries. If
uplo="L", then A is lower triangular and x[-dl]
stores the n*(n-1)/2 strictly lower triangular entries. If
diag="N", then x[du] (uplo="U") or x[dl]
(uplo="L") stores the n diagonal entries of A.
If diag="U", then A is unit triangular and those
elements of x are unreferenced.
“Complementary” class unpackedMatrix
representing conventional (or “unpacked”) dense format
matrices. Generic function unpack, an
alternative to explicit coercion to unpackedMatrix.
showClass("packedMatrix") showMethods(classes = "packedMatrix") (s0 <- new("nsyMatrix")) (M2 <- Matrix(c(TRUE, NA, FALSE, FALSE), 2, 2)) # logical dense (ltr) (sM <- M2 & t(M2)) # -> "lge" class(sM <- as(sM, "nMatrix")) # -> "nge" (sM <- as(sM, "symmetricMatrix")) # -> "nsy" str(sM <- as(sM, "packedMatrix")) # -> "nsp", i.e., packed symmetric (M2 <- Matrix(c(TRUE, NA, FALSE, FALSE), 2, 2)) # logical dense (ltr) str(M2) # can (sM <- M2 | t(M2)) # "lge" as(sM, "symmetricMatrix") str(sM <- as(sM, "packedMatrix")) # packed symmetric ## Only upper triangular part matters (when uplo == "U" as per default) (sy2 <- new("dsyMatrix", Dim = as.integer(c(2,2)), x = c(14, NA,32,77))) str(t(sy2)) # uplo = "L", and the lower tri. (i.e. NA is replaced). chol(sy2) #-> "Cholesky" matrix (sp2 <- pack(sy2)) # a "dspMatrix" ## Coercing to dpoMatrix gives invalid object: sy3 <- new("dsyMatrix", Dim = as.integer(c(2,2)), x = c(14, -1, 2, -7)) try(as(sy3, "dpoMatrix")) # -> error: not positive definite ## 4x4 example m <- matrix(0,4,4); m[upper.tri(m)] <- 1:6 (sym <- m+t(m)+diag(11:14, 4)) (S1 <- pack(sym)) (S2 <- t(S1)) stopifnot(all(S1 == S2)) # equal "seen as matrix", but differ internally : str(S1) S2@x showClass("ntrMatrix") str(new("ntpMatrix")) (nutr <- as(upper.tri(matrix(, 4, 4)), "ndenseMatrix")) str(nutp <- pack(nutr)) # packed matrix: only 10 = 4*(4+1)/2 entries !nutp # the logical negation (is *not* logical triangular !) ## but this one is: stopifnot(all.equal(nutp, pack(!!nutp))) showClass("ltrMatrix") str(new("ltpMatrix")) (lutr <- as(upper.tri(matrix(, 4, 4)), "ldenseMatrix")) str(lutp <- pack(lutr)) # packed matrix: only 10 = 4*(4+1)/2 entries !lutp # the logical negation (is *not* logical triangular !) ## but this one is: stopifnot(all.equal(lutp, pack(!!lutp))) (m <- rbind(2:3, 0:-1)+0) (M <- as(m, "generalMatrix")) (T <- as(M, "triangularMatrix")) # formally upper triangular (T2 <- as(t(M), "triangularMatrix")) stopifnot(T@uplo == "U", T2@uplo == "L", identical(T2, t(T))) m <- matrix(0,4,4); m[upper.tri(m)] <- 1:6 (t1 <- Matrix(m+diag(,4))) str(t1p <- pack(t1)) (t1pu <- diagN2U(t1p)) stopifnot(exprs = { inherits(t1 , "dtrMatrix"); validObject(t1) inherits(t1p, "dtpMatrix"); validObject(t1p) inherits(t1pu,"dtCMatrix"); validObject(t1pu) t1pu@x == 1:6 all(t1pu == t1p) identical((t1pu - t1)@x, numeric())# sparse all-0 }) showClass("dtpMatrix") (p1 <- pack(T2)) str(p1) (pp <- pack(T)) ip1 <- solve(p1) stopifnot(length(p1@x) == 3, length(pp@x) == 3, p1 @ uplo == T2 @ uplo, pp @ uplo == T @ uplo, identical(t(pp), p1), identical(t(p1), pp), all((l.d <- p1 - T2) == 0), is(l.d, "dtpMatrix"), all((u.d <- pp - T ) == 0), is(u.d, "dtpMatrix"), l.d@uplo == T2@uplo, u.d@uplo == T@uplo, identical(t(ip1), solve(pp)), is(ip1, "dtpMatrix"), all.equal(as(solve(p1,p1), "diagonalMatrix"), Diagonal(2)))showClass("packedMatrix") showMethods(classes = "packedMatrix") (s0 <- new("nsyMatrix")) (M2 <- Matrix(c(TRUE, NA, FALSE, FALSE), 2, 2)) # logical dense (ltr) (sM <- M2 & t(M2)) # -> "lge" class(sM <- as(sM, "nMatrix")) # -> "nge" (sM <- as(sM, "symmetricMatrix")) # -> "nsy" str(sM <- as(sM, "packedMatrix")) # -> "nsp", i.e., packed symmetric (M2 <- Matrix(c(TRUE, NA, FALSE, FALSE), 2, 2)) # logical dense (ltr) str(M2) # can (sM <- M2 | t(M2)) # "lge" as(sM, "symmetricMatrix") str(sM <- as(sM, "packedMatrix")) # packed symmetric ## Only upper triangular part matters (when uplo == "U" as per default) (sy2 <- new("dsyMatrix", Dim = as.integer(c(2,2)), x = c(14, NA,32,77))) str(t(sy2)) # uplo = "L", and the lower tri. (i.e. NA is replaced). chol(sy2) #-> "Cholesky" matrix (sp2 <- pack(sy2)) # a "dspMatrix" ## Coercing to dpoMatrix gives invalid object: sy3 <- new("dsyMatrix", Dim = as.integer(c(2,2)), x = c(14, -1, 2, -7)) try(as(sy3, "dpoMatrix")) # -> error: not positive definite ## 4x4 example m <- matrix(0,4,4); m[upper.tri(m)] <- 1:6 (sym <- m+t(m)+diag(11:14, 4)) (S1 <- pack(sym)) (S2 <- t(S1)) stopifnot(all(S1 == S2)) # equal "seen as matrix", but differ internally : str(S1) S2@x showClass("ntrMatrix") str(new("ntpMatrix")) (nutr <- as(upper.tri(matrix(, 4, 4)), "ndenseMatrix")) str(nutp <- pack(nutr)) # packed matrix: only 10 = 4*(4+1)/2 entries !nutp # the logical negation (is *not* logical triangular !) ## but this one is: stopifnot(all.equal(nutp, pack(!!nutp))) showClass("ltrMatrix") str(new("ltpMatrix")) (lutr <- as(upper.tri(matrix(, 4, 4)), "ldenseMatrix")) str(lutp <- pack(lutr)) # packed matrix: only 10 = 4*(4+1)/2 entries !lutp # the logical negation (is *not* logical triangular !) ## but this one is: stopifnot(all.equal(lutp, pack(!!lutp))) (m <- rbind(2:3, 0:-1)+0) (M <- as(m, "generalMatrix")) (T <- as(M, "triangularMatrix")) # formally upper triangular (T2 <- as(t(M), "triangularMatrix")) stopifnot(T@uplo == "U", T2@uplo == "L", identical(T2, t(T))) m <- matrix(0,4,4); m[upper.tri(m)] <- 1:6 (t1 <- Matrix(m+diag(,4))) str(t1p <- pack(t1)) (t1pu <- diagN2U(t1p)) stopifnot(exprs = { inherits(t1 , "dtrMatrix"); validObject(t1) inherits(t1p, "dtpMatrix"); validObject(t1p) inherits(t1pu,"dtCMatrix"); validObject(t1pu) t1pu@x == 1:6 all(t1pu == t1p) identical((t1pu - t1)@x, numeric())# sparse all-0 }) showClass("dtpMatrix") (p1 <- pack(T2)) str(p1) (pp <- pack(T)) ip1 <- solve(p1) stopifnot(length(p1@x) == 3, length(pp@x) == 3, p1 @ uplo == T2 @ uplo, pp @ uplo == T @ uplo, identical(t(pp), p1), identical(t(p1), pp), all((l.d <- p1 - T2) == 0), is(l.d, "dtpMatrix"), all((u.d <- pp - T ) == 0), is(u.d, "dtpMatrix"), l.d@uplo == T2@uplo, u.d@uplo == T@uplo, identical(t(ip1), solve(pp)), is(ip1, "dtpMatrix"), all.equal(as(solve(p1,p1), "diagonalMatrix"), Diagonal(2)))
posdefMatrix is a virtual subclass of
symmetricMatrix representing positive
semidefinite matrices. Positive semidefinite matrices tend to arise
as the product of a matrix and its conjugate tranpose
(ct(x) %*% x or x %*% ct(x); see
ct-methods). In particular, covariance and
correlation matrices are positive semidefinite.
posdefMatrix was not defined until Matrix version 1.8-0.
Dim, Dimnames
inherited from virtual superclass
Matrix.
factorsinherited from virtual superclass
symmetricMatrix.
The direct, nonvirtual subclasses of posdefMatrix defined in
package Matrix are listed below with links to virtual
superclasses defining their data type and storage format.
| Nonvirtual subclass | Data type | Storage format |
dpoMatrix |
dMatrix |
unpackedMatrix
|
zpoMatrix |
zMatrix |
unpackedMatrix
|
dppMatrix |
dMatrix |
packedMatrix
|
zppMatrix |
zMatrix |
packedMatrix
|
dpCMatrix |
dMatrix |
CsparseMatrix
|
zpCMatrix |
zMatrix |
CsparseMatrix
|
dpRMatrix |
dMatrix |
RsparseMatrix
|
zpRMatrix |
zMatrix |
RsparseMatrix
|
dpTMatrix |
dMatrix |
TsparseMatrix
|
zpTMatrix |
zMatrix |
TsparseMatrix
|
The subclasses of zMatrix, CsparseMatrix,
RsparseMatrix, and TsparseMatrix were not defined until
Matrix version 1.8-0.
Each of the above extends a nonvirtual class ds.Matrix or
zs.Matrix representing Hermitian or symmetric matrices more
generally; dpoMatrix and dppMatrix are extended by
nonvirtual classes corMatrix and copMatrix representing
correlation matrices. For implementation details, see the help topic
for the storage format.
Tests for positive semidefiniteness in finite precision arithmetic are
generally expensive and inexact. Validity methods for nonvirtual
subclasses of posdefMatrix defined in package Matrix test
only that the diagonal entries of the represented matrix are
nonnegative (a necessary, not sufficient condition). Meanwhile,
methods for coercion to posdefMatrix defined in package
Matrix test that the represented matrix has a Cholesky
factorization (a sufficient, not necessary condition, being equivalent
to positive definiteness) by evaluating a suitable call to
Cholesky. A more rigorous test for positive
semidefiniteness, supporting matrices which are not positive definite,
would use the Bunch-Kaufman or pivoted Cholesky factorization; see
BunchKaufman and
Cholesky.
Related classes
generalMatrix,
symmetricMatrix,
triangularMatrix,
diagonalMatrix, and
indexMatrix representing
general (unstructured, possibly nonsquare), Hermitian or symmetric,
triangular, diagonal, and index matrices. Generic functions
crossprod and tcrossprod
for a common way to generate positive semidefinite matrices. Generic
function Cholesky for (pivoted or unpivoted)
Cholesky factorization of positive semidefinite matrices. Generic
function chol for getting the upper triangular
Cholesky factor.
h6 <- Hilbert(6) rcond(h6) str(h6) h6 * 27720 # is ``integer'' solve(h6) str(hp6 <- pack(h6)) ### Note that as(*, "corMatrix") *scales* the matrix (ch6 <- as(h6, "corMatrix")) stopifnot(all.equal(as(h6 * 27720, "dsyMatrix"), round(27720 * h6), tolerance = 1e-14), all.equal(ch6@sd^(-2), 2*(1:6)-1, tolerance = 1e-12)) chch <- Cholesky(ch6, perm = FALSE) stopifnot(identical(chch, ch6@factors[["denseCholesky+-"]]), all(abs(crossprod(as(chch, "dtrMatrix")) - ch6) < 1e-10))h6 <- Hilbert(6) rcond(h6) str(h6) h6 * 27720 # is ``integer'' solve(h6) str(hp6 <- pack(h6)) ### Note that as(*, "corMatrix") *scales* the matrix (ch6 <- as(h6, "corMatrix")) stopifnot(all.equal(as(h6 * 27720, "dsyMatrix"), round(27720 * h6), tolerance = 1e-14), all.equal(ch6@sd^(-2), 2*(1:6)-1, tolerance = 1e-12)) chch <- Cholesky(ch6, perm = FALSE) stopifnot(identical(chch, ch6@factors[["denseCholesky+-"]]), all(abs(crossprod(as(chch, "dtrMatrix")) - ch6) < 1e-10))
Format and print sparse matrices flexibly. These are the “workhorses” used by
the format, show and print
methods for sparse matrices. If x is large,
printSpMatrix2(x) calls printSpMatrix() twice, namely,
for the first and the last few rows, suppressing those in between, and
also suppresses columns when x is too wide.
printSpMatrix() basically prints the result of
formatSpMatrix().
formatSpMatrix(x, digits = NULL, maxp = 1e9, cld = getClassDef(class(x)), zero.print = ".", col.names, note.dropping.colnames = TRUE, uniDiag = TRUE, align = c("fancy", "right"), ...) printSpMatrix(x, digits = NULL, maxp = max(100L, getOption("max.print")), cld = getClassDef(class(x)), zero.print = ".", col.names, note.dropping.colnames = TRUE, uniDiag = TRUE, col.trailer = "", align = c("fancy", "right"), ...) printSpMatrix2(x, digits = NULL, maxp = max(100L, getOption("max.print")), zero.print = ".", col.names, note.dropping.colnames = TRUE, uniDiag = TRUE, suppRows = NULL, suppCols = NULL, col.trailer = if(suppCols) "......" else "", align = c("fancy", "right"), width = getOption("width"), fitWidth = TRUE, ...)formatSpMatrix(x, digits = NULL, maxp = 1e9, cld = getClassDef(class(x)), zero.print = ".", col.names, note.dropping.colnames = TRUE, uniDiag = TRUE, align = c("fancy", "right"), ...) printSpMatrix(x, digits = NULL, maxp = max(100L, getOption("max.print")), cld = getClassDef(class(x)), zero.print = ".", col.names, note.dropping.colnames = TRUE, uniDiag = TRUE, col.trailer = "", align = c("fancy", "right"), ...) printSpMatrix2(x, digits = NULL, maxp = max(100L, getOption("max.print")), zero.print = ".", col.names, note.dropping.colnames = TRUE, uniDiag = TRUE, suppRows = NULL, suppCols = NULL, col.trailer = if(suppCols) "......" else "", align = c("fancy", "right"), width = getOption("width"), fitWidth = TRUE, ...)
x |
an R object inheriting from class |
digits |
significant digits to use for printing, see
|
maxp |
integer, default from |
cld |
the class definition of |
zero.print |
character which should be printed for
structural zeroes. The default |
col.names |
logical or string specifying if and how column names of
|
note.dropping.colnames |
logical specifying, when
|
uniDiag |
logical indicating if the diagonal entries of a sparse
unit triangular or unit-diagonal matrix should be formatted as
|
col.trailer |
a string to be appended to the right of each
column; this is typically made use of by |
suppRows, suppCols
|
logicals or |
align |
a string specifying how the |
width |
number, a positive integer, indicating the approximately
desired (line) width of the output, see also |
fitWidth |
logical indicating if some effort should be made to
match the desired |
... |
unused optional arguments. |
If x is large, only the first rows making up the
approximately first maxp entries is used, otherwise all of x.
.formatSparseSimple() is applied to (a dense version
of) the matrix. Then, formatSparseM is used, unless
in trivial cases or for sparse matrices without x slot.
formatSpMatrix() |
returns a character matrix with possibly empty
column names, depending on |
printSpMatrix*() |
return |
Martin Maechler
the virtual class sparseMatrix and the
classes extending it; maybe sparseMatrix or
spMatrix as simple constructors of such matrices.
The underlying utilities formatSparseM and
.formatSparseSimple() (on the same page).
f1 <- gl(5, 3, labels = LETTERS[1:5]) X <- as(f1, "sparseMatrix") X ## <==> show(X) <==> print(X) t(X) ## shows column names, since only 5 columns X2 <- as(gl(12, 3, labels = paste(LETTERS[1:12],"c",sep=".")), "sparseMatrix") X2 ## less nice, but possible: print(X2, col.names = TRUE) # use [,1] [,2] .. => does not fit ## Possibilities with column names printing: t(X2) # suppressing column names print(t(X2), col.names=TRUE) print(t(X2), zero.print = "", col.names="abbr. 1") print(t(X2), zero.print = "-", col.names="substring 2")f1 <- gl(5, 3, labels = LETTERS[1:5]) X <- as(f1, "sparseMatrix") X ## <==> show(X) <==> print(X) t(X) ## shows column names, since only 5 columns X2 <- as(gl(12, 3, labels = paste(LETTERS[1:12],"c",sep=".")), "sparseMatrix") X2 ## less nice, but possible: print(X2, col.names = TRUE) # use [,1] [,2] .. => does not fit ## Possibilities with column names printing: t(X2) # suppressing column names print(t(X2), col.names=TRUE) print(t(X2), zero.print = "", col.names="abbr. 1") print(t(X2), zero.print = "-", col.names="substring 2")
Computes the pivoted QR factorization of an
real matrix , which has the general form
or (equivalently)
where
and are permutation matrices,
is an orthogonal matrix
equal to the product of Householder matrices , and
is an upper trapezoidal matrix.
denseMatrix use the default method implemented
in base, namely qr.default. It is built on
LINPACK routine dqrdc and LAPACK routine dgeqp3, which
do not pivot rows, so that is an identity matrix.
Methods for sparseMatrix are built on
CXSparse routines cs_sqr and cs_qr, which require
.
qr(x, ...) ## S4 method for signature 'CsparseMatrix' qr(x, order = 3L, ...)qr(x, ...) ## S4 method for signature 'CsparseMatrix' qr(x, order = 3L, ...)
x |
a finite matrix or
|
order |
an integer in |
... |
further arguments passed to or from methods. |
If x is sparse and structurally rank deficient, having
structural rank , then x is augmented with
rows of (partly non-structural) zeros, such that
the augmented matrix has structural rank .
This augmented matrix is factorized as described above:
where denotes the original, user-supplied
matrix.
An object representing the factorization, inheriting from
virtual S4 class QR or S3 class
qr. The specific class is qr
unless x inherits from virtual class
sparseMatrix, in which case it is
sparseQR.
Davis, T. A. (2006). Direct methods for sparse linear systems. Society for Industrial and Applied Mathematics. doi:10.1137/1.9780898718881
Golub, G. H., & Van Loan, C. F. (2013). Matrix computations (4th ed.). Johns Hopkins University Press. doi:10.56021/9781421407944
Class sparseQR and its methods.
Class dgCMatrix.
Generic function qr from base,
whose default method qr.default “defines”
the S3 class qr of dense QR factorizations.
Generic functions expand1 and expand2,
for constructing matrix factors from the result.
Generic functions Cholesky, BunchKaufman,
Schur, and lu,
for computing other factorizations.
showMethods("qr", inherited = FALSE) ## Rank deficient: columns 3 {b2} and 6 {c3} are "extra" M <- as(cbind(a1 = 1, b1 = rep(c(1, 0), each = 3L), b2 = rep(c(0, 1), each = 3L), c1 = rep(c(1, 0, 0), 2L), c2 = rep(c(0, 1, 0), 2L), c3 = rep(c(0, 0, 1), 2L)), "CsparseMatrix") rownames(M) <- paste0("r", seq_len(nrow(M))) b <- 1:6 eps <- .Machine$double.eps ## .... [1] full rank .................................................. ## ===> a least squares solution of A x = b exists ## and is unique _in exact arithmetic_ (A1 <- M[, -c(3L, 6L)]) (qr.A1 <- qr(A1)) stopifnot(exprs = { rankMatrix(A1) == ncol(A1) { d1 <- abs(diag(qr.A1@R)); sum(d1 < max(d1) * eps) == 0L } rcond(crossprod(A1)) >= eps all.equal(qr.coef(qr.A1, b), drop(solve(crossprod(A1), crossprod(A1, b)))) all.equal(qr.fitted(qr.A1, b) + qr.resid(qr.A1, b), b) }) ## .... [2] numerically rank deficient with full structural rank ....... ## ===> a least squares solution of A x = b does not ## exist or is not unique _in exact arithmetic_ (A2 <- M) (qr.A2 <- qr(A2)) stopifnot(exprs = { rankMatrix(A2) == ncol(A2) - 2L { d2 <- abs(diag(qr.A2@R)); sum(d2 < max(d2) * eps) == 2L } rcond(crossprod(A2)) < eps ## 'qr.coef' computes unique least squares solution of "nearby" problem ## Z x = b for some full rank Z ~ A, currently without warning {FIXME} ! tryCatch({ qr.coef(qr.A2, b); TRUE }, condition = function(x) FALSE) all.equal(qr.fitted(qr.A2, b) + qr.resid(qr.A2, b), b) }) ## .... [3] numerically and structurally rank deficient ................ ## ===> factorization of _augmented_ matrix with ## full structural rank proceeds as in [2] ## NB: implementation details are subject to change; see (*) below A3 <- M A3[, c(3L, 6L)] <- 0 A3 (qr.A3 <- qr(A3)) # with a warning ... "additional 2 row(s) of zeros" stopifnot(exprs = { ## sparseQR object preserves the unaugmented dimensions (*) dim(qr.A3 ) == dim(A3) dim(qr.A3@V) == dim(A3) + c(2L, 0L) dim(qr.A3@R) == dim(A3) + c(2L, 0L) ## The augmented matrix remains numerically rank deficient rankMatrix(A3) == ncol(A3) - 2L { d3 <- abs(diag(qr.A3@R)); sum(d3 < max(d3) * eps) == 2L } rcond(crossprod(A3)) < eps }) ## Auxiliary functions accept and return a vector or matrix ## with dimensions corresponding to the unaugmented matrix (*), ## in all cases with a warning qr.coef (qr.A3, b) qr.fitted(qr.A3, b) qr.resid (qr.A3, b) ## .... [4] yet more examples .......................................... ## By disabling column pivoting, one gets the "vanilla" factorization ## A = Q~ R, where Q~ := P1' Q is orthogonal because P1 and Q are (qr.A1.pp <- qr(A1, order = 0L)) # partial pivoting ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) stopifnot(exprs = { length(qr.A1 @q) == ncol(A1) length(qr.A1.pp@q) == 0L # indicating no column pivoting ae2(A1[, qr.A1@q + 1L], qr.Q(qr.A1 ) %*% qr.R(qr.A1 )) ae2(A1 , qr.Q(qr.A1.pp) %*% qr.R(qr.A1.pp)) })showMethods("qr", inherited = FALSE) ## Rank deficient: columns 3 {b2} and 6 {c3} are "extra" M <- as(cbind(a1 = 1, b1 = rep(c(1, 0), each = 3L), b2 = rep(c(0, 1), each = 3L), c1 = rep(c(1, 0, 0), 2L), c2 = rep(c(0, 1, 0), 2L), c3 = rep(c(0, 0, 1), 2L)), "CsparseMatrix") rownames(M) <- paste0("r", seq_len(nrow(M))) b <- 1:6 eps <- .Machine$double.eps ## .... [1] full rank .................................................. ## ===> a least squares solution of A x = b exists ## and is unique _in exact arithmetic_ (A1 <- M[, -c(3L, 6L)]) (qr.A1 <- qr(A1)) stopifnot(exprs = { rankMatrix(A1) == ncol(A1) { d1 <- abs(diag(qr.A1@R)); sum(d1 < max(d1) * eps) == 0L } rcond(crossprod(A1)) >= eps all.equal(qr.coef(qr.A1, b), drop(solve(crossprod(A1), crossprod(A1, b)))) all.equal(qr.fitted(qr.A1, b) + qr.resid(qr.A1, b), b) }) ## .... [2] numerically rank deficient with full structural rank ....... ## ===> a least squares solution of A x = b does not ## exist or is not unique _in exact arithmetic_ (A2 <- M) (qr.A2 <- qr(A2)) stopifnot(exprs = { rankMatrix(A2) == ncol(A2) - 2L { d2 <- abs(diag(qr.A2@R)); sum(d2 < max(d2) * eps) == 2L } rcond(crossprod(A2)) < eps ## 'qr.coef' computes unique least squares solution of "nearby" problem ## Z x = b for some full rank Z ~ A, currently without warning {FIXME} ! tryCatch({ qr.coef(qr.A2, b); TRUE }, condition = function(x) FALSE) all.equal(qr.fitted(qr.A2, b) + qr.resid(qr.A2, b), b) }) ## .... [3] numerically and structurally rank deficient ................ ## ===> factorization of _augmented_ matrix with ## full structural rank proceeds as in [2] ## NB: implementation details are subject to change; see (*) below A3 <- M A3[, c(3L, 6L)] <- 0 A3 (qr.A3 <- qr(A3)) # with a warning ... "additional 2 row(s) of zeros" stopifnot(exprs = { ## sparseQR object preserves the unaugmented dimensions (*) dim(qr.A3 ) == dim(A3) dim(qr.A3@V) == dim(A3) + c(2L, 0L) dim(qr.A3@R) == dim(A3) + c(2L, 0L) ## The augmented matrix remains numerically rank deficient rankMatrix(A3) == ncol(A3) - 2L { d3 <- abs(diag(qr.A3@R)); sum(d3 < max(d3) * eps) == 2L } rcond(crossprod(A3)) < eps }) ## Auxiliary functions accept and return a vector or matrix ## with dimensions corresponding to the unaugmented matrix (*), ## in all cases with a warning qr.coef (qr.A3, b) qr.fitted(qr.A3, b) qr.resid (qr.A3, b) ## .... [4] yet more examples .......................................... ## By disabling column pivoting, one gets the "vanilla" factorization ## A = Q~ R, where Q~ := P1' Q is orthogonal because P1 and Q are (qr.A1.pp <- qr(A1, order = 0L)) # partial pivoting ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) stopifnot(exprs = { length(qr.A1 @q) == ncol(A1) length(qr.A1.pp@q) == 0L # indicating no column pivoting ae2(A1[, qr.A1@q + 1L], qr.Q(qr.A1 ) %*% qr.R(qr.A1 )) ae2(A1 , qr.Q(qr.A1.pp) %*% qr.R(qr.A1.pp)) })
Compute ‘the’ matrix rank, a well-defined functional in theory(*), somewhat ambiguous in practice. We provide several methods, the default corresponding to Matlab's definition.
(*) The rank of a matrix , ,
is the maximal number of linearly independent columns (or rows); hence
.
rankMatrix(x, tol = NULL, method = c("tolNorm2", "qr.R", "qrLINPACK", "qr", "useGrad", "maybeGrad"), sval = svd(x, 0, 0)$d, warn.t = TRUE, warn.qr = TRUE) qr2rankMatrix(qr, tol = NULL, isBqr = is.qr(qr), do.warn = TRUE)rankMatrix(x, tol = NULL, method = c("tolNorm2", "qr.R", "qrLINPACK", "qr", "useGrad", "maybeGrad"), sval = svd(x, 0, 0)$d, warn.t = TRUE, warn.qr = TRUE) qr2rankMatrix(qr, tol = NULL, isBqr = is.qr(qr), do.warn = TRUE)
x |
numeric matrix, of dimension |
tol |
nonnegative number specifying a (relative,
“scalefree”) tolerance for testing of
“practically zero” with specific meaning depending on
|
method |
a character string specifying the computational method for the rank, can be abbreviated:
|
sval |
numeric vector of non-increasing singular values of
|
warn.t |
logical indicating if |
warn.qr |
in the |
qr |
an R object resulting from |
isBqr |
|
do.warn |
logical; if true, warn about non-finite diagonal
entries in the |
qr2rankMatrix() is typically called from rankMatrix() for
the "qr"* methods, but can be used directly - much more
efficiently in case the qr-decomposition is available anyway.
If x is a matrix of all 0 (or of zero dimension), the rank
is zero; otherwise, typically a positive integer in 1:min(dim(x))
with attributes detailing the method used.
There are rare cases where the sparse decomposition
“fails” in so far as the diagonal entries of , the
(see above), end with non-finite, typically NaN
entries. Then, a warning is signalled (unless warn.qr /
do.warn is not true) and NA (specifically,
NA_integer_) is returned.
For large sparse matrices x, unless you can specify
sval yourself, currently method = "qr" may
be the only feasible one, as the others need sval and call
svd() which currently coerces x to a
denseMatrix which may be very slow or impossible,
depending on the matrix dimensions.
Note that in the case of sparse x, method = "qr", all
non-strictly zero diagonal entries where counted, up to
including Matrix version 1.1-0, i.e., that method implicitly
used tol = 0, see also the set.seed(42) example below.
Martin Maechler; for the "*Grad" methods building on suggestions by Ravi Varadhan.
rankMatrix(cbind(1, 0, 1:3)) # 2 (meths <- eval(formals(rankMatrix)$method)) ## a "border" case: H12 <- Hilbert(12) rankMatrix(H12, tol = 1e-20) # 12; but 11 with default method & tol. sapply(meths, function(.m.) rankMatrix(H12, method = .m.)) ## tolNorm2 qr.R qrLINPACK qr useGrad maybeGrad ## 11 11 12 12 11 11 ## The meaning of 'tol' for method="qrLINPACK" and *dense* x is not entirely "scale free" rMQL <- function(ex, M) rankMatrix(M, method="qrLINPACK",tol = 10^-ex) rMQR <- function(ex, M) rankMatrix(M, method="qr.R", tol = 10^-ex) sapply(5:15, rMQL, M = H12) # result is platform dependent ## 7 7 8 10 10 11 11 11 12 12 12 {x86_64} sapply(5:15, rMQL, M = 1000 * H12) # not identical unfortunately ## 7 7 8 10 11 11 12 12 12 12 12 sapply(5:15, rMQR, M = H12) ## 5 6 7 8 8 9 9 10 10 11 11 sapply(5:15, rMQR, M = 1000 * H12) # the *same* ## "sparse" case: M15 <- kronecker(diag(x=c(100,1,10)), Hilbert(5)) sapply(meths, function(.m.) rankMatrix(M15, method = .m.)) #--> all 15, but 'useGrad' has 14. sapply(meths, function(.m.) rankMatrix(M15, method = .m., tol = 1e-7)) # all 14 ## "large" sparse n <- 250000; p <- 33; nnz <- 10000 L <- sparseMatrix(i = sample.int(n, nnz, replace=TRUE), j = sample.int(p, nnz, replace=TRUE), x = rnorm(nnz)) (st1 <- system.time(r1 <- rankMatrix(L))) # warning+ ~1.5 sec (2013) (st2 <- system.time(r2 <- rankMatrix(L, method = "qr"))) # considerably faster! r1[[1]] == print(r2[[1]]) ## --> ( 33 TRUE ) ## another sparse-"qr" one, which ``failed'' till 2013-11-23: set.seed(42) f1 <- factor(sample(50, 1000, replace=TRUE)) f2 <- factor(sample(50, 1000, replace=TRUE)) f3 <- factor(sample(50, 1000, replace=TRUE)) D <- t(do.call(rbind, lapply(list(f1,f2,f3), as, 'sparseMatrix'))) dim(D); nnzero(D) ## 1000 x 150 // 3000 non-zeros (= 2%) stopifnot(rankMatrix(D, method='qr') == 148, rankMatrix(crossprod(D),method='qr') == 148) ## zero matrix has rank 0 : stopifnot(sapply(meths, function(.m.) rankMatrix(matrix(0, 2, 2), method = .m.)) == 0)rankMatrix(cbind(1, 0, 1:3)) # 2 (meths <- eval(formals(rankMatrix)$method)) ## a "border" case: H12 <- Hilbert(12) rankMatrix(H12, tol = 1e-20) # 12; but 11 with default method & tol. sapply(meths, function(.m.) rankMatrix(H12, method = .m.)) ## tolNorm2 qr.R qrLINPACK qr useGrad maybeGrad ## 11 11 12 12 11 11 ## The meaning of 'tol' for method="qrLINPACK" and *dense* x is not entirely "scale free" rMQL <- function(ex, M) rankMatrix(M, method="qrLINPACK",tol = 10^-ex) rMQR <- function(ex, M) rankMatrix(M, method="qr.R", tol = 10^-ex) sapply(5:15, rMQL, M = H12) # result is platform dependent ## 7 7 8 10 10 11 11 11 12 12 12 {x86_64} sapply(5:15, rMQL, M = 1000 * H12) # not identical unfortunately ## 7 7 8 10 11 11 12 12 12 12 12 sapply(5:15, rMQR, M = H12) ## 5 6 7 8 8 9 9 10 10 11 11 sapply(5:15, rMQR, M = 1000 * H12) # the *same* ## "sparse" case: M15 <- kronecker(diag(x=c(100,1,10)), Hilbert(5)) sapply(meths, function(.m.) rankMatrix(M15, method = .m.)) #--> all 15, but 'useGrad' has 14. sapply(meths, function(.m.) rankMatrix(M15, method = .m., tol = 1e-7)) # all 14 ## "large" sparse n <- 250000; p <- 33; nnz <- 10000 L <- sparseMatrix(i = sample.int(n, nnz, replace=TRUE), j = sample.int(p, nnz, replace=TRUE), x = rnorm(nnz)) (st1 <- system.time(r1 <- rankMatrix(L))) # warning+ ~1.5 sec (2013) (st2 <- system.time(r2 <- rankMatrix(L, method = "qr"))) # considerably faster! r1[[1]] == print(r2[[1]]) ## --> ( 33 TRUE ) ## another sparse-"qr" one, which ``failed'' till 2013-11-23: set.seed(42) f1 <- factor(sample(50, 1000, replace=TRUE)) f2 <- factor(sample(50, 1000, replace=TRUE)) f3 <- factor(sample(50, 1000, replace=TRUE)) D <- t(do.call(rbind, lapply(list(f1,f2,f3), as, 'sparseMatrix'))) dim(D); nnzero(D) ## 1000 x 150 // 3000 non-zeros (= 2%) stopifnot(rankMatrix(D, method='qr') == 148, rankMatrix(crossprod(D),method='qr') == 148) ## zero matrix has rank 0 : stopifnot(sapply(meths, function(.m.) rankMatrix(matrix(0, 2, 2), method = .m.)) == 0)
Estimate the reciprocal of the condition number of a matrix.
This is a generic function with several methods, as seen by
showMethods(rcond).
kappa(z, ...) rcond(x, norm, ...) ## S4 method for signature 'sparseMatrix,character' rcond(x, norm, exact = FALSE, inverse = solve(x), warn = TRUE, ...)kappa(z, ...) rcond(x, norm, ...) ## S4 method for signature 'sparseMatrix,character' rcond(x, norm, exact = FALSE, inverse = solve(x), warn = TRUE, ...)
x, z
|
an R object that inherits from the |
norm |
character string indicating the type of norm to be used in
the estimate. The default is |
exact |
. |
inverse |
. |
warn |
. |
... |
further arguments passed to or from other methods. |
An estimate of the reciprocal condition number of x.
The condition number of a regular (square) matrix is the product of
the norm of the matrix and the norm of its inverse (or
pseudo-inverse).
More generally, the condition number is defined (also for
non-square matrices ) as
Whenever x is not a square matrix, in our method
definitions, this is typically computed via rcond(qr.R(qr(X)), ...)
where X is x or t(x).
The condition number takes on values between 1 and infinity, inclusive, and can be viewed as a factor by which errors in solving linear systems with this matrix as coefficient matrix could be magnified.
rcond() computes the reciprocal condition number
with values in and can be viewed as a
scaled measure of how close a matrix is to being rank deficient (aka
“singular”).
Condition numbers are usually estimated, since exact computation is costly in terms of floating-point operations. An (over) estimate of reciprocal condition number is given, since by doing so overflow is avoided. Matrices are well-conditioned if the reciprocal condition number is near 1 and ill-conditioned if it is near zero.
Golub, G., and Van Loan, C. F. (1989). Matrix Computations, 2nd edition, Johns Hopkins, Baltimore.
norm, kappa() from package
base computes an approximate condition number of a
“traditional” matrix, even non-square ones, with respect to the
(Euclidean) norm.
solve.
condest, a newer approximate estimate of
the (1-norm) condition number, particularly efficient for large sparse
matrices.
x <- Matrix(rnorm(9), 3, 3) rcond(x) ## typically "the same" (with more computational effort): 1 / (norm(x) * norm(solve(x))) rcond(Hilbert(9)) # should be about 9.1e-13 ## For non-square matrices: rcond(x1 <- cbind(1,1:10))# 0.05278 rcond(x2 <- cbind(x1, 2:11))# practically 0, since x2 does not have full rank ## sparse (S1 <- Matrix(rbind(0:1,0, diag(3:-2)))) rcond(S1) m1 <- as(S1, "denseMatrix") all.equal(rcond(S1), rcond(m1)) ## wide and sparse rcond(Matrix(cbind(0, diag(2:-1)))) ## Large sparse example ---------- m <- Matrix(c(3,0:2), 2,2) M <- bdiag(kronecker(Diagonal(2), m), kronecker(m,m)) 36*(iM <- solve(M)) # still sparse MM <- kronecker(Diagonal(10), kronecker(Diagonal(5),kronecker(m,M))) dim(M3 <- kronecker(bdiag(M,M),MM)) # 12'800 ^ 2 if(interactive()) ## takes about 2 seconds if you have >= 8 GB RAM system.time(r <- rcond(M3)) ## whereas this is *fast* even though it computes solve(M3) system.time(r. <- rcond(M3, exact=TRUE)) if(interactive()) ## the values are not the same c(r, r.) # 0.05555 0.013888 ## for all norms available for sparseMatrix, except "2" : cbind(rr <- sapply(c("O","I","F","M"), function(N) rcond(M3, norm=N, exact=TRUE)))x <- Matrix(rnorm(9), 3, 3) rcond(x) ## typically "the same" (with more computational effort): 1 / (norm(x) * norm(solve(x))) rcond(Hilbert(9)) # should be about 9.1e-13 ## For non-square matrices: rcond(x1 <- cbind(1,1:10))# 0.05278 rcond(x2 <- cbind(x1, 2:11))# practically 0, since x2 does not have full rank ## sparse (S1 <- Matrix(rbind(0:1,0, diag(3:-2)))) rcond(S1) m1 <- as(S1, "denseMatrix") all.equal(rcond(S1), rcond(m1)) ## wide and sparse rcond(Matrix(cbind(0, diag(2:-1)))) ## Large sparse example ---------- m <- Matrix(c(3,0:2), 2,2) M <- bdiag(kronecker(Diagonal(2), m), kronecker(m,m)) 36*(iM <- solve(M)) # still sparse MM <- kronecker(Diagonal(10), kronecker(Diagonal(5),kronecker(m,M))) dim(M3 <- kronecker(bdiag(M,M),MM)) # 12'800 ^ 2 if(interactive()) ## takes about 2 seconds if you have >= 8 GB RAM system.time(r <- rcond(M3)) ## whereas this is *fast* even though it computes solve(M3) system.time(r. <- rcond(M3, exact=TRUE)) if(interactive()) ## the values are not the same c(r, r.) # 0.05555 0.013888 ## for all norms available for sparseMatrix, except "2" : cbind(rr <- sapply(c("O","I","F","M"), function(N) rcond(M3, norm=N, exact=TRUE)))
TODO.
## S4 method for signature 'sparseVector' rep(x, times, length.out, each, ...)## S4 method for signature 'sparseVector' rep(x, times, length.out, each, ...)
x |
. |
times |
. |
length.out |
. |
each |
. |
... |
. |
rep2abI(x, times) conceptually computes
rep.int(x, times) but with an
abIndex class result.
rep2abI(x, times)rep2abI(x, times)
x |
numeric vector |
times |
integer (valued) scalar: the number of repetitions |
rep.int(), the base function;
abIseq, abIndex.
(ab <- rep2abI(2:7, 4)) stopifnot(identical(as(ab, "numeric"), rep(2:7, 4)))(ab <- rep2abI(2:7, 4)) stopifnot(identical(as(ab, "numeric"), rep(2:7, 4)))
Class "rleDiff" is for compactly storing long vectors
which mainly consist of linear stretches. For such a vector
x, diff(x) consists of constant stretches
and is hence well compressable via rle().
Objects can be created by calls of the form new("rleDiff", ...).
Currently experimental, see below.
first:A single number (of class "numLike",
a class union of "numeric" and "logical").
rle:Object of class "rle", basically a
list with components "lengths" and
"values", see rle(). As this is used to
encode potentially huge index vectors, lengths may be of
type double here.
There is a simple show method only.
This is currently an experimental auxiliary class
for the class abIndex, see there.
showClass("rleDiff") ab <- c(abIseq(2, 100), abIseq(20, -2)) ab@rleD # is "rleDiff"showClass("rleDiff") ab <- c(abIseq(2, 100), abIseq(20, -2)) ab@rleD # is "rleDiff"
Generate a random sparse matrix efficiently. The default has rounded
gaussian non-zero entries, and rand.x = NULL generates random
pattern matrices, i.e. inheriting from nsparseMatrix.
rsparsematrix(nrow, ncol, density, nnz = round(density * maxE), symmetric = FALSE, rand.x = function(n) signif(rnorm(n), 2), ...)rsparsematrix(nrow, ncol, density, nnz = round(density * maxE), symmetric = FALSE, rand.x = function(n) signif(rnorm(n), 2), ...)
nrow, ncol
|
number of rows and columns, i.e., the matrix
dimension ( |
density |
optional number in |
nnz |
number of non-zero entries, for a sparse matrix typically
considerably smaller than |
symmetric |
logical indicating if result should be a matrix of
class |
rand.x |
|
... |
optionally further arguments passed to
|
The algorithm first samples “encoded” s without
replacement, via one dimensional indices, if not symmetric
sample.int(nrow*ncol, nnz), then—if rand.x is
not NULL—gets x <- rand.x(nnz) and calls
sparseMatrix(i=i, j=j, x=x, ..). When
rand.x=NULL, sparseMatrix(i=i, j=j, ..) will
return a pattern matrix (i.e., inheriting from
nsparseMatrix).
a sparseMatrix, say M of dimension (nrow,
ncol), i.e., with dim(M) == c(nrow, ncol), if symmetric
is not true, with nzM <- nnzero(M) fulfilling
nzM <= nnz and typically, nzM == nnz.
Martin Maechler
set.seed(17)# to be reproducible M <- rsparsematrix(8, 12, nnz = 30) # small example, not very sparse M M1 <- rsparsematrix(1000, 20, nnz = 123, rand.x = runif) summary(M1) ## a random *symmetric* Matrix (S9 <- rsparsematrix(9, 9, nnz = 10, symmetric=TRUE)) # dsCMatrix nnzero(S9)# ~ 20: as 'nnz' only counts one "triangle" ## a random patter*n* aka boolean Matrix (no 'x' slot): (n7 <- rsparsematrix(5, 12, nnz = 10, rand.x = NULL)) ## a [T]riplet representation sparseMatrix: T2 <- rsparsematrix(40, 12, nnz = 99, repr = "T") head(T2)set.seed(17)# to be reproducible M <- rsparsematrix(8, 12, nnz = 30) # small example, not very sparse M M1 <- rsparsematrix(1000, 20, nnz = 123, rand.x = runif) summary(M1) ## a random *symmetric* Matrix (S9 <- rsparsematrix(9, 9, nnz = 10, symmetric=TRUE)) # dsCMatrix nnzero(S9)# ~ 20: as 'nnz' only counts one "triangle" ## a random patter*n* aka boolean Matrix (no 'x' slot): (n7 <- rsparsematrix(5, 12, nnz = 10, rand.x = NULL)) ## a [T]riplet representation sparseMatrix: T2 <- rsparsematrix(40, 12, nnz = 99, repr = "T") head(T2)
RsparseMatrix is a virtual subclass of
sparseMatrix representing compressed sparse row
(CSR) format matrices. To represent an m-by-n matrix
A, this format stores the positions of m*n or fewer
(often ) entries of A,
ordering these by row then by column. Authors of subclasses of
RsparseMatrix are free to declare how this information is used
to specify A. See ‘Subclasses’ for subclasses defined
in package Matrix.
Dim, Dimnames
inherited from virtual superclass
Matrix.
pan integer vector of length Dim[1]+1
corresponding to a subset V of the set of entries of
A. p[i+1] is the number of elements of V
belonging to one of the first i rows of A, implying
0 = p[1] <= p[i] <= p[i+1] <= p[length(p)] = |V|
where |V| denotes the size of V. The number of
elements of V belonging to row i of A is
given by p[i+1]-p[i] or, equivalently, diff(p)[i].
jan integer vector of length p[length(p)]
storing the 0-based column indices of the elements of V
ordered by row then by column. Hence, to be valid, j must
satisfy 0 <= j < Dim[2] and be increasing within the
contiguous segments that partition it by row of A. The
segment corresponding to row i can be accessed as
j[(p[i]+1):p[i+1]] if p[i] < p[i+1] and by
j[seq.int(from=p[i], length.out=p[i+1]-p[i])] more
generally. Experimentally, length(j) is allowed to exceed
p[length(p)]; if it does, then the excess elements of
j are unreferenced.
The nonvirtual subclasses of RsparseMatrix defined in package
Matrix are listed below with links to virtual superclasses
defining their data type and structure.
| Nonvirtual subclass | Data type | Structure |
ngRMatrix |
nMatrix |
generalMatrix
|
lgRMatrix |
lMatrix |
generalMatrix
|
igRMatrix |
iMatrix |
generalMatrix
|
dgRMatrix |
dMatrix |
generalMatrix
|
zgRMatrix |
zMatrix |
generalMatrix
|
nsRMatrix |
nMatrix |
symmetricMatrix
|
lsRMatrix |
lMatrix |
symmetricMatrix
|
isRMatrix |
iMatrix |
symmetricMatrix
|
dsRMatrix |
dMatrix |
symmetricMatrix
|
zsRMatrix |
zMatrix |
symmetricMatrix
|
dpRMatrix |
dMatrix |
posdefMatrix
|
zpRMatrix |
zMatrix |
posdefMatrix
|
ntRMatrix |
nMatrix |
triangularMatrix
|
ltRMatrix |
lMatrix |
triangularMatrix
|
itRMatrix |
iMatrix |
triangularMatrix
|
dtRMatrix |
dMatrix |
triangularMatrix
|
ztRMatrix |
zMatrix |
triangularMatrix
|
The subclasses of iMatrix, zMatrix, and
posdefMatrix were not defined until Matrix version 1.8-0.
Classes .gRMatrix represent general (unstructured, possibly
nonsquare) A. Objects have p and j slots
specifying a subset V of the set of entries of A, as
described in ‘Slots’. For ngRMatrix, whose data type is
boolean, the entries in V have value 1, and the entries not in
V have value 0. For other .gRMatrix, the entries in
V have values taken from an additional x slot (a
logical, integer, double, or complex vector), and the entries not in
V have value 0. The j and x slots are entirely
parallel, both using the ordering of V by row then by column.
Classes .sRMatrix represent Hermitian or symmetric A.
Compared to .gRMatrix, objects have an additional uplo
slot indicating a restriction on V. If uplo="U", then
V contains only upper triangular entries of A. If
uplo="L", then V contains only lower triangular entries
of A. The entries in V have value 1 (nsRMatrix)
or values taken from an x slot (other .sRMatrix). The
entries opposite the main diagonal, namely A[j, i] for all
A[i, j] in V, have value op(A[i, j]), where
op=Conj for Hermitian A and op=identity for
symmetric A. All other entries of A have value 0.
Objects of class zsRMatrix have an additional trans
slot that distinguishes Hermitian and symmetric A, which use
trans="C" and "T", respectively. If trans="C"
and V contains diagonal entries of A, then the imaginary
parts of the corresponding elements of x are not referenced.
(The diagonal entries of Hermitian matrices are real by definition.)
Classes dpRMatrix and zpRMatrix extend dsRMatrix
and zsRMatrix and represent positive semidefinite A.
Positive semidefiniteness of A induces a constraint on the
x slot. However, this constraint is not strictly enforced by
the validity methods, which test only that the diagonal entries of
A are nonnegative (a necessary, not sufficient condition).
For zpRMatrix, only trans="C" is valid.
Classes .tRMatrix represent triangular A. Compared to
.gRMatrix, objects have additional uplo and diag
slots indicating restrictions on V. If uplo="U", then
A is upper triangular and V contains only upper
triangular entries. If uplo="L", then A is lower
triangular and V contains only lower triangular entries. If
diag="U" (instead of "N"), then A is unit
triangular and V contains only strictly upper or lower
triangular entries. With the exception of diagonal entries when
diag="U", which have value 1, entries not in V have
value 0.
“Sister” classes CsparseMatrix and
TsparseMatrix for compressed sparse column and
triplet format matrices. Generic functions
rbind2, rowSums,
[ (when called as x[i, ]), etc., whose
methods for RsparseMatrix are particularly efficient.
showClass("RsparseMatrix") (m0 <- new("dsRMatrix")) m2 <- new("dsRMatrix", Dim = c(2L,2L), x = c(3,1), j = c(1L,1L), p = 0:2) m2 stopifnot(colSums(as(m2, "TsparseMatrix")) == 3:4) str(m2) (ds2 <- forceSymmetric(diag(2))) # dsy* dR <- as(ds2, "RsparseMatrix") dR # dsRMatrix (m0 <- new("dtRMatrix")) (m2 <- new("dtRMatrix", Dim = c(2L,2L), x = c(5, 1:2), p = c(0L,2:3), j= c(0:1,1L))) str(m2) (m3 <- as(Diagonal(2), "RsparseMatrix"))# --> dtRMatrixshowClass("RsparseMatrix") (m0 <- new("dsRMatrix")) m2 <- new("dsRMatrix", Dim = c(2L,2L), x = c(3,1), j = c(1L,1L), p = 0:2) m2 stopifnot(colSums(as(m2, "TsparseMatrix")) == 3:4) str(m2) (ds2 <- forceSymmetric(diag(2))) # dsy* dR <- as(ds2, "RsparseMatrix") dR # dsRMatrix (m0 <- new("dtRMatrix")) (m2 <- new("dtRMatrix", Dim = c(2L,2L), x = c(5, 1:2), p = c(0L,2:3), j= c(0:1,1L))) str(m2) (m3 <- as(Diagonal(2), "RsparseMatrix"))# --> dtRMatrix
Computes the Schur factorization of an
real matrix , which has the general form
where
is an orthogonal matrix and
is a block upper triangular matrix with
and diagonal blocks
specifying the real and complex conjugate eigenvalues of .
The column vectors of are the Schur vectors of ,
and is the Schur form of .
Methods are built on LAPACK routine dgees.
Schur(x, vectors = TRUE, ...)Schur(x, vectors = TRUE, ...)
x |
|
vectors |
a logical. If |
... |
further arguments passed to or from methods. |
An object representing the factorization, inheriting
from virtual class SchurFactorization.
Currently, the specific class is always Schur.
The LAPACK source code, including documentation; see https://netlib.org/lapack/double/dgees.f.
Golub, G. H., & Van Loan, C. F. (2013). Matrix computations (4th ed.). Johns Hopkins University Press. doi:10.56021/9781421407944
Class Schur and its methods.
Class dgeMatrix.
Generic functions expand1 and expand2,
for constructing matrix factors from the result.
Generic functions Cholesky, BunchKaufman,
lu, and qr,
for computing other factorizations.
showMethods("Schur", inherited = FALSE) set.seed(0) Schur(Hilbert(9L)) # real eigenvalues n <- 5L (A <- Matrix(round(rnorm(n * n, sd = 100)), n, n)) (sch.A <- Schur(A)) # complex eigenvalues ## A ~ Q T Q' in floating point str(e.sch.A <- expand2(sch.A), max.level = 2L) stopifnot(all.equal(A, Reduce(`%*%`, e.sch.A))) (e1 <- eigen(matrix(sch.A@x, n, n), only.values = TRUE)$values) (e2 <- eigen( A , only.values = TRUE)$values) (e3 <- sch.A@values) stopifnot(exprs = { all.equal(e1, e2, tolerance = 1e-13) all.equal(e1, e3[order(Mod(e3), decreasing = TRUE)], tolerance = 1e-13) identical(Schur(A, vectors = FALSE), `slot<-`(sch.A, "vectors", TRUE, double(0L))) })showMethods("Schur", inherited = FALSE) set.seed(0) Schur(Hilbert(9L)) # real eigenvalues n <- 5L (A <- Matrix(round(rnorm(n * n, sd = 100)), n, n)) (sch.A <- Schur(A)) # complex eigenvalues ## A ~ Q T Q' in floating point str(e.sch.A <- expand2(sch.A), max.level = 2L) stopifnot(all.equal(A, Reduce(`%*%`, e.sch.A))) (e1 <- eigen(matrix(sch.A@x, n, n), only.values = TRUE)$values) (e2 <- eigen( A , only.values = TRUE)$values) (e3 <- sch.A@values) stopifnot(exprs = { all.equal(e1, e2, tolerance = 1e-13) all.equal(e1, e3[order(Mod(e3), decreasing = TRUE)], tolerance = 1e-13) identical(Schur(A, vectors = FALSE), `slot<-`(sch.A, "vectors", TRUE, double(0L))) })
solve
Methods for generic function solve for solving
linear systems of equations,
i.e., for in ,
where is a square matrix and and are matrices
with dimensions consistent with .
solve(a, b, ...) ## S4 method for signature 'denseMatrix,missing' solve(a, b, tol = .Machine$double.eps, ...) ## S4 method for signature 'denseMatrix,denseMatrix' solve(a, b, tol = .Machine$double.eps, ...) ## S4 method for signature 'CsparseMatrix,missing' solve(a, b, sparse = TRUE, ...) ## S4 method for signature 'CsparseMatrix,denseMatrix' solve(a, b, sparse = FALSE, ...) ## S4 method for signature 'CsparseMatrix,CsparseMatrix' solve(a, b, sparse = TRUE, ...) ## S4 method for signature 'denseLU,denseMatrix' solve(a, b, ...) ## S4 method for signature 'denseBunchKaufman,denseMatrix' solve(a, b, ...) ## S4 method for signature 'denseCholesky,denseMatrix' solve(a, b, ...) ## S4 method for signature 'sparseQR,CsparseMatrix' solve(a, b, sparse = TRUE, ...) ## S4 method for signature 'sparseLU,CsparseMatrix' solve(a, b, sparse = TRUE, tol = .Machine$double.eps, ...) ## S4 method for signature 'sparseCholesky,CsparseMatrix' solve(a, b, sparse = TRUE, system = c("A", "LDLt", "LD", "DLt", "L", "Lt", "D", "P", "Pt"), ...)solve(a, b, ...) ## S4 method for signature 'denseMatrix,missing' solve(a, b, tol = .Machine$double.eps, ...) ## S4 method for signature 'denseMatrix,denseMatrix' solve(a, b, tol = .Machine$double.eps, ...) ## S4 method for signature 'CsparseMatrix,missing' solve(a, b, sparse = TRUE, ...) ## S4 method for signature 'CsparseMatrix,denseMatrix' solve(a, b, sparse = FALSE, ...) ## S4 method for signature 'CsparseMatrix,CsparseMatrix' solve(a, b, sparse = TRUE, ...) ## S4 method for signature 'denseLU,denseMatrix' solve(a, b, ...) ## S4 method for signature 'denseBunchKaufman,denseMatrix' solve(a, b, ...) ## S4 method for signature 'denseCholesky,denseMatrix' solve(a, b, ...) ## S4 method for signature 'sparseQR,CsparseMatrix' solve(a, b, sparse = TRUE, ...) ## S4 method for signature 'sparseLU,CsparseMatrix' solve(a, b, sparse = TRUE, tol = .Machine$double.eps, ...) ## S4 method for signature 'sparseCholesky,CsparseMatrix' solve(a, b, sparse = TRUE, system = c("A", "LDLt", "LD", "DLt", "L", "Lt", "D", "P", "Pt"), ...)
a |
a finite square matrix or
|
b |
a vector, |
tol |
a non-negative number. For |
sparse |
a logical indicating if the result should be formally
sparse, i.e., if the result should inherit from virtual class
|
system |
a string specifying a linear system to be solved.
Only methods for |
... |
further arguments passed to or from methods. |
Methods for general and symmetric matrices a compute a
triangular factorization (LU, Bunch-Kaufman, or Cholesky)
and call the method for the corresponding factorization class.
The factorization is sparse if a is. Methods for sparse,
symmetric matrices a attempt a Cholesky factorization
and perform an LU factorization only if that fails (typically
because a is not positive definite).
Triangular, diagonal, and permutation matrices do not require
factorization (they are already “factors”), hence methods
for those are implemented directly. For triangular a,
solutions are obtained by forward or backward substitution;
for diagonal a, they are obtained by scaling the rows
of b; and for permutations a, they are obtained
by permuting the rows of b.
Methods for dense a are built on 14 LAPACK routines:
class d..Matrix, where ..=(ge|tr|tp|sy|sp|po|pp),
uses routines d..tri and d..trs for missing
and non-missing b, respectively. A corollary is that
these methods always give a dense result.
Methods for sparse a are built on CXSparse routines
cs_lsolve, cs_usolve, and cs_spsolve and
CHOLMOD routines cholmod_solve and cholmod_spsolve.
By default, these methods give a vector result if b
is a vector, a sparse matrix result if b is missing
or a sparse matrix, and a dense matrix result if b
is a dense matrix. One can override this behaviour by setting
the sparse argument, where available, but that should
be done with care. Note that a sparse result may be sparse only
in the formal sense and not at all in the mathematical sense,
depending on the nonzero patterns of a and b.
Furthermore, whereas dense results are fully preallocated,
sparse results must be “grown” in a loop over the columns
of b.
Methods for a of class sparseQR
are simple wrappers around qr.coef, giving the
least squares solution in overdetermined cases.
Methods for a inheriting from CHMfactor
can solve systems other than the default one .
The correspondence between its system argument the system
actually solved is outlined in the table below.
See CHMfactor-class for a definition of notation.
system |
isLDL(a)=TRUE |
isLDL(a)=FALSE
|
"A" |
|
|
"LDLt" |
|
|
"LD" |
|
|
"DLt" |
|
|
"L" |
|
|
"Lt" |
|
|
"D" |
|
|
"P" |
|
|
"Pt" |
|
|
Virtual class MatrixFactorization and its
subclasses.
Generic functions Cholesky, BunchKaufman,
Schur, lu, and qr for
computing factorizations.
Generic function solve from base.
Function qr.coef from base for computing
least squares solutions of overdetermined linear systems.
## A close to symmetric example with "quite sparse" inverse: n1 <- 7; n2 <- 3 dd <- data.frame(a = gl(n1,n2), b = gl(n2,1,n1*n2))# balanced 2-way X <- sparse.model.matrix(~ -1+ a + b, dd)# no intercept --> even sparser XXt <- tcrossprod(X) diag(XXt) <- rep(c(0,0,1,0), length.out = nrow(XXt)) n <- nrow(ZZ <- kronecker(XXt, Diagonal(x=c(4,1)))) image(a <- 2*Diagonal(n) + ZZ %*% Diagonal(x=c(10, rep(1, n-1)))) isSymmetric(a) # FALSE image(drop0(skewpart(a))) image(ia0 <- solve(a, tol = 0)) # checker board, dense [but really, a is singular!] try(solve(a, sparse=TRUE))##-> error [ TODO: assertError ] ia. <- solve(a, sparse=TRUE, tol = 1e-19)##-> *no* error if(R.version$arch == "x86_64") ## Fails on 32-bit [Fedora 19, R 3.0.2] from Matrix 1.1-0 on [FIXME ??] only stopifnot(all.equal(as.matrix(ia.), as.matrix(ia0))) a <- a + Diagonal(n) iad <- solve(a) ias <- solve(a, sparse=FALSE) stopifnot(all.equal(as(iad,"denseMatrix"), ias, tolerance=1e-14)) I. <- iad %*% a ; image(I.) I0 <- drop0(zapsmall(I.)); image(I0) .I <- a %*% iad .I0 <- drop0(zapsmall(.I)) stopifnot( all.equal(as(I0, "diagonalMatrix"), Diagonal(n)), all.equal(as(.I0,"diagonalMatrix"), Diagonal(n)) )## A close to symmetric example with "quite sparse" inverse: n1 <- 7; n2 <- 3 dd <- data.frame(a = gl(n1,n2), b = gl(n2,1,n1*n2))# balanced 2-way X <- sparse.model.matrix(~ -1+ a + b, dd)# no intercept --> even sparser XXt <- tcrossprod(X) diag(XXt) <- rep(c(0,0,1,0), length.out = nrow(XXt)) n <- nrow(ZZ <- kronecker(XXt, Diagonal(x=c(4,1)))) image(a <- 2*Diagonal(n) + ZZ %*% Diagonal(x=c(10, rep(1, n-1)))) isSymmetric(a) # FALSE image(drop0(skewpart(a))) image(ia0 <- solve(a, tol = 0)) # checker board, dense [but really, a is singular!] try(solve(a, sparse=TRUE))##-> error [ TODO: assertError ] ia. <- solve(a, sparse=TRUE, tol = 1e-19)##-> *no* error if(R.version$arch == "x86_64") ## Fails on 32-bit [Fedora 19, R 3.0.2] from Matrix 1.1-0 on [FIXME ??] only stopifnot(all.equal(as.matrix(ia.), as.matrix(ia0))) a <- a + Diagonal(n) iad <- solve(a) ias <- solve(a, sparse=FALSE) stopifnot(all.equal(as(iad,"denseMatrix"), ias, tolerance=1e-14)) I. <- iad %*% a ; image(I.) I0 <- drop0(zapsmall(I.)); image(I0) .I <- a %*% iad .I0 <- drop0(zapsmall(.I)) stopifnot( all.equal(as(I0, "diagonalMatrix"), Diagonal(n)), all.equal(as(.I0,"diagonalMatrix"), Diagonal(n)) )
TODO.
## S4 method for signature 'sparseVector' sort(x, decreasing = FALSE, na.last = NA, ...)## S4 method for signature 'sparseVector' sort(x, decreasing = FALSE, na.last = NA, ...)
x |
. |
decreasing |
. |
na.last |
. |
... |
. |
Construct a sparse model or “design” matrix,
from a formula and data frame (sparse.model.matrix) or a single
factor (fac2sparse).
The fac2[Ss]parse() functions are utilities, also used
internally in the principal user level function
sparse.model.matrix().
sparse.model.matrix(object, data = environment(object), contrasts.arg = NULL, xlev = NULL, transpose = FALSE, drop.unused.levels = FALSE, row.names = TRUE, sep = "", verbose = FALSE, ...) fac2sparse(from, to = c("d", "l", "n"), drop.unused.levels = TRUE, repr = c("C", "R", "T"), giveCsparse) fac2Sparse(from, to = c("d", "l", "n"), drop.unused.levels = TRUE, repr = c("C", "R", "T"), giveCsparse, factorPatt12, contrasts.arg = NULL)sparse.model.matrix(object, data = environment(object), contrasts.arg = NULL, xlev = NULL, transpose = FALSE, drop.unused.levels = FALSE, row.names = TRUE, sep = "", verbose = FALSE, ...) fac2sparse(from, to = c("d", "l", "n"), drop.unused.levels = TRUE, repr = c("C", "R", "T"), giveCsparse) fac2Sparse(from, to = c("d", "l", "n"), drop.unused.levels = TRUE, repr = c("C", "R", "T"), giveCsparse, factorPatt12, contrasts.arg = NULL)
object |
an object of an appropriate class. For the default method, a model formula or terms object. |
data |
a data frame created with |
contrasts.arg |
|
xlev |
to be used as argument of |
transpose |
logical indicating if the transpose should be
returned; if the transposed is used anyway, setting |
drop.unused.levels |
should factors have unused levels dropped?
The default for |
row.names |
logical indicating if row names should be used. |
sep |
|
verbose |
logical or integer indicating if (and how much) progress output should be printed. |
... |
further arguments passed to or from other methods. |
from |
(for |
to |
a character indicating the “kind” of sparse matrix to
be returned. The default, |
giveCsparse |
deprecated, replaced with |
repr |
|
factorPatt12 |
logical vector, say |
a sparse matrix, extending CsparseMatrix (for
fac2sparse() if repr = "C" as per default; a
TsparseMatrix or RsparseMatrix, otherwise).
For fac2Sparse(), a list of length two, both
components with the corresponding transposed model matrix, where the
corresponding factorPatt12 is true.
fac2sparse(), the basic workhorse of
sparse.model.matrix(), returns the transpose
(t) of the model matrix.
model.Matrix(sparse = TRUE) from package
MatrixModels may be preferable nowadays to sparse.model.matrix,
as model.Matrix returns an object of class modelMatrix
with additional slots assign and contrasts relating to
the model variables.
Doug Bates and Martin Maechler, with initial suggestions from Tim Hesterberg.
model.matrix in package stats, part of base R.
model.Matrix in package MatrixModels; see ‘Note’.
as(f, "sparseMatrix") (see coerce(from = "factor", ..)
in the class doc sparseMatrix) produces the
transposed sparse model matrix for a single factor f
(and no contrasts).
dd <- data.frame(a = gl(3,4), b = gl(4,1,12))# balanced 2-way options("contrasts") # the default: "contr.treatment" sparse.model.matrix(~ a + b, dd) sparse.model.matrix(~ -1+ a + b, dd)# no intercept --> even sparser sparse.model.matrix(~ a + b, dd, contrasts.arg = list(a = "contr.sum")) sparse.model.matrix(~ a + b, dd, contrasts.arg = list(b = "contr.SAS")) ## Sparse method is equivalent to the traditional one : stopifnot(all(sparse.model.matrix(~ a + b, dd) == Matrix(model.matrix(~ a + b, dd), sparse=TRUE)), all(sparse.model.matrix(~0 + a + b, dd) == Matrix(model.matrix(~0 + a + b, dd), sparse=TRUE))) (ff <- gl(3,4,, c("X","Y", "Z"))) fac2sparse(ff) # 3 x 12 sparse Matrix of class "dgCMatrix" ## ## X 1 1 1 1 . . . . . . . . ## Y . . . . 1 1 1 1 . . . . ## Z . . . . . . . . 1 1 1 1 ## can also be computed via sparse.model.matrix(): f30 <- gl(3,0 ) f12 <- gl(3,0, 12) stopifnot( all.equal(t( fac2sparse(ff) ), sparse.model.matrix(~ 0+ff), tolerance = 0, check.attributes=FALSE), is(M <- fac2sparse(f30, drop= TRUE),"CsparseMatrix"), dim(M) == c(0, 0), is(M <- fac2sparse(f30, drop=FALSE),"CsparseMatrix"), dim(M) == c(3, 0), is(M <- fac2sparse(f12, drop= TRUE),"CsparseMatrix"), dim(M) == c(0,12), is(M <- fac2sparse(f12, drop=FALSE),"CsparseMatrix"), dim(M) == c(3,12) )dd <- data.frame(a = gl(3,4), b = gl(4,1,12))# balanced 2-way options("contrasts") # the default: "contr.treatment" sparse.model.matrix(~ a + b, dd) sparse.model.matrix(~ -1+ a + b, dd)# no intercept --> even sparser sparse.model.matrix(~ a + b, dd, contrasts.arg = list(a = "contr.sum")) sparse.model.matrix(~ a + b, dd, contrasts.arg = list(b = "contr.SAS")) ## Sparse method is equivalent to the traditional one : stopifnot(all(sparse.model.matrix(~ a + b, dd) == Matrix(model.matrix(~ a + b, dd), sparse=TRUE)), all(sparse.model.matrix(~0 + a + b, dd) == Matrix(model.matrix(~0 + a + b, dd), sparse=TRUE))) (ff <- gl(3,4,, c("X","Y", "Z"))) fac2sparse(ff) # 3 x 12 sparse Matrix of class "dgCMatrix" ## ## X 1 1 1 1 . . . . . . . . ## Y . . . . 1 1 1 1 . . . . ## Z . . . . . . . . 1 1 1 1 ## can also be computed via sparse.model.matrix(): f30 <- gl(3,0 ) f12 <- gl(3,0, 12) stopifnot( all.equal(t( fac2sparse(ff) ), sparse.model.matrix(~ 0+ff), tolerance = 0, check.attributes=FALSE), is(M <- fac2sparse(f30, drop= TRUE),"CsparseMatrix"), dim(M) == c(0, 0), is(M <- fac2sparse(f30, drop=FALSE),"CsparseMatrix"), dim(M) == c(3, 0), is(M <- fac2sparse(f12, drop= TRUE),"CsparseMatrix"), dim(M) == c(0,12), is(M <- fac2sparse(f12, drop=FALSE),"CsparseMatrix"), dim(M) == c(3,12) )
CHMfactor is the virtual class of sparse Cholesky
factorizations of real, symmetric
matrices , having the general form
or (equivalently)
where
is a permutation matrix,
is a unit lower triangular matrix,
is a diagonal matrix, and
.
The second equalities hold only for positive semidefinite ,
for which the diagonal entries of are non-negative
and is well-defined.
The implementation of class CHMfactor is based on
CHOLMOD's C-level cholmod_factor_struct. Virtual
subclasses CHMsimpl and CHMsuper separate
the simplicial and supernodal variants. These have nonvirtual
subclasses [dn]CHMsimpl and [dn]CHMsuper,
where prefix ‘d’ and prefix ‘n’ are reserved
for numeric and symbolic factorizations, respectively.
isLDL(x)isLDL(x)
x |
an object inheriting from virtual class |
isLDL(x) returns TRUE or FALSE:
TRUE if x stores the lower triangular entries
of ,
FALSE if x stores the lower triangular entries
of .
Of CHMfactor:
Dim, Dimnames
inherited from virtual class
MatrixFactorization.
colcountan integer vector of length Dim[1]
giving an estimate of the number of nonzero entries in
each column of the lower triangular Cholesky factor.
If symbolic analysis was performed prior to factorization,
then the estimate is exact.
perma 0-based integer vector of length Dim[1]
specifying the permutation applied to the rows and columns
of the factorized matrix. perm of length 0 is valid and
equivalent to the identity permutation, implying no pivoting.
typean integer vector of length 6 specifying
details of the factorization. The elements correspond to
members ordering, is_ll, is_super,
is_monotonic, maxcsize, and maxesize
of the original cholmod_factor_struct.
Simplicial and supernodal factorizations are distinguished
by is_super. Simplicial factorizations do not use
maxcsize or maxesize. Supernodal factorizations
do not use is_ll or is_monotonic.
Of CHMsimpl (all unused by nCHMsimpl):
nzan integer vector of length Dim[1]
giving the number of nonzero entries in each column of the
lower triangular Cholesky factor. There is at least one
nonzero entry in each column, because the diagonal elements
of the factor are stored explicitly.
pan integer vector of length Dim[1]+1.
Row indices of nonzero entries in column j of the
lower triangular Cholesky factor are obtained as
i[p[j]+seq_len(nz[j])]+1.
ian integer vector of length greater than or equal
to sum(nz) containing the row indices of nonzero entries
in the lower triangular Cholesky factor. These are grouped by
column and sorted within columns, but the columns themselves
need not be ordered monotonically. Columns may be overallocated,
i.e., the number of elements of i reserved for column
j may exceed nz[j].
prv, nxt
integer vectors of length
Dim[1]+2 indicating the order in which the columns of
the lower triangular Cholesky factor are stored in i
and x.
Starting from j <- Dim[1]+2,
the recursion j <- nxt[j+1]+1 traverses the columns
in forward order and terminates when nxt[j+1] = -1.
Starting from j <- Dim[1]+1,
the recursion j <- prv[j+1]+1 traverses the columns
in backward order and terminates when prv[j+1] = -1.
Of dCHMsimpl:
xa numeric vector parallel to i containing
the corresponding nonzero entries of the lower triangular
Cholesky factor or (if and only if type[2]
is 0) of the lower triangular matrix .
Of CHMsuper:
super, pi, px
integer vectors of
length nsuper+1, where nsuper is the number of
supernodes. super[j]+1 is the index of the leftmost
column of supernode j. The row indices of supernode
j are obtained as s[pi[j]+seq_len(pi[j+1]-pi[j])]+1.
The numeric entries of supernode j are obtained as
x[px[j]+seq_len(px[j+1]-px[j])]+1 (if slot x
is available).
san integer vector of length greater than or equal
to Dim[1] containing the row indices of the supernodes.
s may contain duplicates, but not within a supernode,
where the row indices must be increasing.
Of dCHMsuper:
xa numeric vector of length less than or equal to
prod(Dim) containing the numeric entries of the supernodes.
Class MatrixFactorization, directly.
Objects can be generated directly by calls of the form
new("dCHMsimpl", ...), etc., but dCHMsimpl and
dCHMsuper are more typically obtained as the value of
Cholesky(x, ...) for x inheriting from
sparseMatrix
(often dsCMatrix).
There is currently no API outside of calls to new
for generating nCHMsimpl and nCHMsuper. These
classes are vestigial and may be formally deprecated in a future
version of Matrix.
coercesignature(from = "CHMsimpl", to = "dtCMatrix"):
returns a dtCMatrix representing
the lower triangular Cholesky factor or
the lower triangular matrix ,
the latter if and only if from@type[2] is 0.
coercesignature(from = "CHMsuper", to = "dgCMatrix"):
returns a dgCMatrix representing
the lower triangular Cholesky factor . Note that,
for supernodes spanning two or more columns, the supernodal
algorithm by design stores non-structural zeros above
the main diagonal, hence dgCMatrix is
indeed more appropriate than dtCMatrix
as a coercion target.
determinantsignature(x = "CHMfactor", logarithm = "logical"):
behaves according to an optional argument sqrt.
If sqrt = FALSE, then this method computes the determinant
of the factorized matrix or its logarithm.
If sqrt = TRUE, then this method computes the determinant
of the factor or
its logarithm, giving NaN for the modulus when
has negative diagonal elements. For backwards compatibility,
the default value of sqrt is TRUE, but that can
be expected change in a future version of Matrix, hence
defensive code will always set sqrt (to TRUE,
if the code must remain backwards compatible with Matrix
< 1.6-0). Calls to this method not setting sqrt
may warn about the pending change. The warnings can be disabled
with options(Matrix.warnSqrtDefault = 0).
diagsignature(x = "CHMfactor"):
returns a numeric vector of length containing the diagonal
elements of , which (if they are all non-negative)
are the squared diagonal elements of .
expandsignature(x = "CHMfactor"):
see expand-methods.
expand1signature(x = "CHMsimpl"):
see expand1-methods.
expand1signature(x = "CHMsuper"):
see expand1-methods.
expand2signature(x = "CHMsimpl"):
see expand2-methods.
expand2signature(x = "CHMsuper"):
see expand2-methods.
imagesignature(x = "CHMfactor"):
see image-methods.
nnzerosignature(x = "CHMfactor"):
see nnzero-methods.
solvesignature(a = "CHMfactor", b = .):
see solve-methods.
updatesignature(object = "CHMfactor"):
returns a copy of object with the same nonzero pattern
but with numeric entries updated according to additional
arguments parent and mult, where parent
is (coercible to) a dsCMatrix or a
dgCMatrix and mult is a numeric
vector of positive length.
The numeric entries are updated with those of the Cholesky
factor of F(parent) + mult[1] * I, i.e.,
F(parent) plus mult[1] times the identity matrix,
where F = identity for symmetric parent
and F = tcrossprod for other parent.
The nonzero pattern of F(parent) must match
that of S if object = Cholesky(S, ...).
updownsignature(update = ., C = ., object = "CHMfactor"):
see updown-methods.
The CHOLMOD source code; see
https://github.com/DrTimothyAldenDavis/SuiteSparse,
notably the header file ‘CHOLMOD/Include/cholmod.h’
defining cholmod_factor_struct.
Chen, Y., Davis, T. A., Hager, W. W., & Rajamanickam, S. (2008). Algorithm 887: CHOLMOD, supernodal sparse Cholesky factorization and update/downdate. ACM Transactions on Mathematical Software, 35(3), Article 22, 1-14. doi:10.1145/1391989.1391995
Amestoy, P. R., Davis, T. A., & Duff, I. S. (2004). Algorithm 837: AMD, an approximate minimum degree ordering algorithm. ACM Transactions on Mathematical Software, 17(4), 886-905. doi:10.1145/1024074.1024081
Golub, G. H., & Van Loan, C. F. (2013). Matrix computations (4th ed.). Johns Hopkins University Press. doi:10.56021/9781421407944
Class dsCMatrix.
Generic functions Cholesky, updown,
expand1 and expand2.
showClass("sparseCholesky") set.seed(2) m <- 1000L n <- 200L M <- rsparsematrix(m, n, 0.01) A <- crossprod(M) ## With dimnames, to see that they are propagated : dimnames(A) <- dn <- rep.int(list(paste0("x", seq_len(n))), 2L) (ch.A <- Cholesky(A)) # pivoted, by default str(e.ch.A <- expand2(ch.A, LDL = TRUE), max.level = 2L) str(E.ch.A <- expand2(ch.A, LDL = FALSE), max.level = 2L) ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) ## A ~ P1' L1 D L1' P1 ~ P1' L L' P1 in floating point stopifnot(exprs = { identical(names(e.ch.A), c("P1.", "L1", "D", "L1.", "P1")) identical(names(E.ch.A), c("P1.", "L" , "L." , "P1")) identical(e.ch.A[["P1"]], new("pMatrix", Dim = c(n, n), Dimnames = c(list(NULL), dn[2L]), margin = 2L, perm = invertPerm(ch.A@perm, 0L, 1L))) identical(e.ch.A[["P1."]], t(e.ch.A[["P1"]])) identical(e.ch.A[["L1."]], t(e.ch.A[["L1"]])) identical(E.ch.A[["L." ]], t(E.ch.A[["L" ]])) identical(e.ch.A[["D"]], Diagonal(x = diag(ch.A))) all.equal(E.ch.A[["L"]], with(e.ch.A, L1 %*% sqrt(D))) ae1(A, with(e.ch.A, P1. %*% L1 %*% D %*% L1. %*% P1)) ae1(A, with(E.ch.A, P1. %*% L %*% L. %*% P1)) ae2(A[ch.A@perm + 1L, ch.A@perm + 1L], with(e.ch.A, L1 %*% D %*% L1.)) ae2(A[ch.A@perm + 1L, ch.A@perm + 1L], with(E.ch.A, L %*% L. )) }) ## Factorization handled as factorized matrix ## (in some cases only optionally, depending on arguments) b <- rnorm(n) stopifnot(all.equal(det(A), det(ch.A, sqrt = FALSE)), all.equal(solve(A, b), solve(ch.A, b, system = "A"))) u1 <- update(ch.A, A , mult = sqrt(2)) u2 <- update(ch.A, t(M), mult = sqrt(2)) # updating with crossprod(M), not M stopifnot(all.equal(u1, u2, tolerance = 1e-14))showClass("sparseCholesky") set.seed(2) m <- 1000L n <- 200L M <- rsparsematrix(m, n, 0.01) A <- crossprod(M) ## With dimnames, to see that they are propagated : dimnames(A) <- dn <- rep.int(list(paste0("x", seq_len(n))), 2L) (ch.A <- Cholesky(A)) # pivoted, by default str(e.ch.A <- expand2(ch.A, LDL = TRUE), max.level = 2L) str(E.ch.A <- expand2(ch.A, LDL = FALSE), max.level = 2L) ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) ## A ~ P1' L1 D L1' P1 ~ P1' L L' P1 in floating point stopifnot(exprs = { identical(names(e.ch.A), c("P1.", "L1", "D", "L1.", "P1")) identical(names(E.ch.A), c("P1.", "L" , "L." , "P1")) identical(e.ch.A[["P1"]], new("pMatrix", Dim = c(n, n), Dimnames = c(list(NULL), dn[2L]), margin = 2L, perm = invertPerm(ch.A@perm, 0L, 1L))) identical(e.ch.A[["P1."]], t(e.ch.A[["P1"]])) identical(e.ch.A[["L1."]], t(e.ch.A[["L1"]])) identical(E.ch.A[["L." ]], t(E.ch.A[["L" ]])) identical(e.ch.A[["D"]], Diagonal(x = diag(ch.A))) all.equal(E.ch.A[["L"]], with(e.ch.A, L1 %*% sqrt(D))) ae1(A, with(e.ch.A, P1. %*% L1 %*% D %*% L1. %*% P1)) ae1(A, with(E.ch.A, P1. %*% L %*% L. %*% P1)) ae2(A[ch.A@perm + 1L, ch.A@perm + 1L], with(e.ch.A, L1 %*% D %*% L1.)) ae2(A[ch.A@perm + 1L, ch.A@perm + 1L], with(E.ch.A, L %*% L. )) }) ## Factorization handled as factorized matrix ## (in some cases only optionally, depending on arguments) b <- rnorm(n) stopifnot(all.equal(det(A), det(ch.A, sqrt = FALSE)), all.equal(solve(A, b), solve(ch.A, b, system = "A"))) u1 <- update(ch.A, A , mult = sqrt(2)) u2 <- update(ch.A, t(M), mult = sqrt(2)) # updating with crossprod(M), not M stopifnot(all.equal(u1, u2, tolerance = 1e-14))
sparseLU is the class of sparse, row- and column-pivoted
LU factorizations of real matrices ,
having the general form
or (equivalently)
where
and are permutation matrices,
is a unit lower triangular matrix, and
is an upper triangular matrix.
Dim, Dimnames
inherited from virtual class
MatrixFactorization.
Lan object of class dtCMatrix,
the unit lower triangular factor.
Uan object of class dtCMatrix,
the upper triangular factor.
p, q
0-based integer vectors of length
Dim[1],
specifying the permutations applied to the rows and columns of
the factorized matrix. q of length 0 is valid and
equivalent to the identity permutation, implying no column pivoting.
Using R syntax, the matrix
is precisely A[p+1, q+1]
(A[p+1, ] when q has length 0).
Class LU, directly.
Class MatrixFactorization, by class
LU, distance 2.
Objects can be generated directly by calls of the form
new("sparseLU", ...), but they are more typically obtained
as the value of lu(x) for x inheriting from
sparseMatrix (often dgCMatrix).
determinantsignature(x = "sparseLU", logarithm = "logical"):
computes the determinant of the factorized matrix
or its logarithm.
expandsignature(x = "sparseLU"):
see expand-methods.
expand1signature(x = "sparseLU"):
see expand1-methods.
expand2signature(x = "sparseLU"):
see expand2-methods.
solvesignature(a = "sparseLU", b = .):
see solve-methods.
Davis, T. A. (2006). Direct methods for sparse linear systems. Society for Industrial and Applied Mathematics. doi:10.1137/1.9780898718881
Golub, G. H., & Van Loan, C. F. (2013). Matrix computations (4th ed.). Johns Hopkins University Press. doi:10.56021/9781421407944
Class denseLU for dense LU factorizations.
Class dgCMatrix.
Generic functions lu,
expand1 and expand2.
showClass("sparseLU") set.seed(2) A <- as(readMM(system.file("external", "pores_1.mtx", package = "Matrix")), "CsparseMatrix") (n <- A@Dim[1L]) ## With dimnames, to see that they are propagated : dimnames(A) <- dn <- list(paste0("r", seq_len(n)), paste0("c", seq_len(n))) (lu.A <- lu(A)) str(e.lu.A <- expand2(lu.A), max.level = 2L) ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) ## A ~ P1' L U P2' in floating point stopifnot(exprs = { identical(names(e.lu.A), c("P1.", "L", "U", "P2.")) identical(e.lu.A[["P1."]], new("pMatrix", Dim = c(n, n), Dimnames = c(dn[1L], list(NULL)), margin = 1L, perm = invertPerm(lu.A@p, 0L, 1L))) identical(e.lu.A[["P2."]], new("pMatrix", Dim = c(n, n), Dimnames = c(list(NULL), dn[2L]), margin = 2L, perm = invertPerm(lu.A@q, 0L, 1L))) identical(e.lu.A[["L"]], lu.A@L) identical(e.lu.A[["U"]], lu.A@U) ae1(A, with(e.lu.A, P1. %*% L %*% U %*% P2.)) ae2(A[lu.A@p + 1L, lu.A@q + 1L], with(e.lu.A, L %*% U)) }) ## Factorization handled as factorized matrix b <- rnorm(n) stopifnot(identical(det(A), det(lu.A)), identical(solve(A, b), solve(lu.A, b)))showClass("sparseLU") set.seed(2) A <- as(readMM(system.file("external", "pores_1.mtx", package = "Matrix")), "CsparseMatrix") (n <- A@Dim[1L]) ## With dimnames, to see that they are propagated : dimnames(A) <- dn <- list(paste0("r", seq_len(n)), paste0("c", seq_len(n))) (lu.A <- lu(A)) str(e.lu.A <- expand2(lu.A), max.level = 2L) ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) ## A ~ P1' L U P2' in floating point stopifnot(exprs = { identical(names(e.lu.A), c("P1.", "L", "U", "P2.")) identical(e.lu.A[["P1."]], new("pMatrix", Dim = c(n, n), Dimnames = c(dn[1L], list(NULL)), margin = 1L, perm = invertPerm(lu.A@p, 0L, 1L))) identical(e.lu.A[["P2."]], new("pMatrix", Dim = c(n, n), Dimnames = c(list(NULL), dn[2L]), margin = 2L, perm = invertPerm(lu.A@q, 0L, 1L))) identical(e.lu.A[["L"]], lu.A@L) identical(e.lu.A[["U"]], lu.A@U) ae1(A, with(e.lu.A, P1. %*% L %*% U %*% P2.)) ae2(A[lu.A@p + 1L, lu.A@q + 1L], with(e.lu.A, L %*% U)) }) ## Factorization handled as factorized matrix b <- rnorm(n) stopifnot(identical(det(A), det(lu.A)), identical(solve(A, b), solve(lu.A, b)))
User-friendly construction of sparse matrices (inheriting from
virtual class CsparseMatrix,
RsparseMatrix, or
TsparseMatrix)
from the positions and values of their nonzero entries.
This interface is recommended over direct construction via
calls such as new("..[CRT]Matrix", ...).
sparseMatrix(i, j, p, x, dims, dimnames, symmetric = FALSE, triangular = FALSE, index1 = TRUE, repr = c("C", "R", "T"), giveCsparse, check = TRUE, use.last.ij = FALSE, int2dbl = )sparseMatrix(i, j, p, x, dims, dimnames, symmetric = FALSE, triangular = FALSE, index1 = TRUE, repr = c("C", "R", "T"), giveCsparse, check = TRUE, use.last.ij = FALSE, int2dbl = )
i, j
|
integer vectors of equal length specifying the positions
(row and column indices) of the nonzero (or non- |
p |
integer vector of pointers, one for each column (or row),
to the initial (zero-based) index of elements in the column (or row).
Exactly one of |
x |
optional, typically nonzero values for the matrix entries.
If specified, then the length must equal that of |
dims |
optional length-2 integer vector of matrix dimensions.
If missing, then |
dimnames |
optional list of |
symmetric |
logical indicating if the resulting matrix should
be symmetric. In that case, |
triangular |
logical indicating if the resulting matrix should
be triangular. In that case, |
index1 |
logical. If |
repr |
|
giveCsparse |
(deprecated, replaced by |
check |
logical indicating whether to check that the result is
formally valid before returning. Do not set to |
use.last.ij |
logical indicating if, in the case of repeated
(duplicated) pairs |
int2dbl |
|
Exactly one of the arguments i, j and p must be
missing.
In typical usage, p is missing, i and j are
vectors of positive integers and x is a numeric vector. These
three vectors, which must have the same length, form the triplet
representation of the sparse matrix.
If i or j is missing then p must be a
non-decreasing integer vector whose first element is zero. It
provides the compressed, or “pointer” representation of the row
or column indices, whichever is missing. The expanded form of p,
rep(seq_along(dp),dp) where dp <- diff(p), is used as
the (1-based) row or column indices.
You cannot set both singular and triangular to true;
rather use Diagonal() (or its alternatives, see there).
The values of i, j, p and index1 are used
to create 1-based index vectors i and j from which a
TsparseMatrix is constructed, with numerical
values given by x, if non-missing. Note that in that case,
when some pairs are repeated (aka
“duplicated”), the corresponding are added, in
consistency with the definition of the
TsparseMatrix class, unless use.last.ij
is set to true.
By default, when repr = "C", the CsparseMatrix
derived from this triplet form is returned, where repr = "R" now
allows to directly get an RsparseMatrix and
repr = "T" leaves the result as TsparseMatrix.
The reason for returning a CsparseMatrix object
instead of the triplet format by default is that the compressed column
form is easier to work with when performing matrix operations. In
particular, if there are no zeros in x then a
CsparseMatrix is a unique representation of the
sparse matrix.
A sparse matrix, by default in compressed sparse column format and
(formally) without symmetric or triangular structure, i.e.,
by default inheriting from both CsparseMatrix
and generalMatrix.
You do need to use index1 = FALSE (or add + 1
to i and j) if you want use the 0-based i (and
j) slots from existing sparse matrices.
Matrix(*, sparse=TRUE) for the constructor of
such matrices from a dense matrix. That is easier in small
sample, but much less efficient (or impossible) for large matrices,
where something like sparseMatrix() is needed.
Further bdiag and Diagonal for (block-)diagonal and
bandSparse for banded sparse matrix constructors.
Random sparse matrices via rsparsematrix().
The standard R xtabs(*, sparse=TRUE), for sparse tables
and sparse.model.matrix() for building sparse model
matrices.
Consider CsparseMatrix and similar class
definition help files.
## simple example i <- c(1,3:8); j <- c(2,9,6:10); x <- 7 * (1:7) (A <- sparseMatrix(i, j, x = x)) ## 8 x 10 "dgCMatrix" summary(A) str(A) # note that *internally* 0-based row indices are used (sA <- sparseMatrix(i, j, x = x, symmetric = TRUE)) ## 10 x 10 "dsCMatrix" (tA <- sparseMatrix(i, j, x = x, triangular= TRUE)) ## 10 x 10 "dtCMatrix" stopifnot( all(sA == tA + t(tA)) , identical(sA, as(tA + t(tA), "symmetricMatrix"))) ## dims can be larger than the maximum row or column indices (AA <- sparseMatrix(c(1,3:8), c(2,9,6:10), x = 7 * (1:7), dims = c(10,20))) summary(AA) ## i, j and x can be in an arbitrary order, as long as they are consistent set.seed(1); (perm <- sample(1:7)) (A1 <- sparseMatrix(i[perm], j[perm], x = x[perm])) stopifnot(identical(A, A1)) ## The slots are 0-index based, so try( sparseMatrix(i=A@i, p=A@p, x= seq_along(A@x)) ) ## fails and you should say so: 1-indexing is FALSE: sparseMatrix(i=A@i, p=A@p, x= seq_along(A@x), index1 = FALSE) ## the (i,j) pairs can be repeated, in which case the x's are summed (args <- data.frame(i = c(i, 1), j = c(j, 2), x = c(x, 2))) (Aa <- do.call(sparseMatrix, args)) ## explicitly ask for elimination of such duplicates, so ## that the last one is used: (A. <- do.call(sparseMatrix, c(args, list(use.last.ij = TRUE)))) stopifnot(Aa[1,2] == 9, # 2+7 == 9 A.[1,2] == 2) # 2 was *after* 7 ## for a pattern matrix, of course there is no "summing": (nA <- do.call(sparseMatrix, args[c("i","j")])) dn <- list(LETTERS[1:3], letters[1:5]) ## pointer vectors can be used, and the (i,x) slots are sorted if necessary: m <- sparseMatrix(i = c(3,1, 3:2, 2:1), p= c(0:2, 4,4,6), x = 1:6, dimnames = dn) m str(m) stopifnot(identical(dimnames(m), dn)) sparseMatrix(x = 2.72, i=1:3, j=2:4) # recycling x sparseMatrix(x = TRUE, i=1:3, j=2:4) # recycling x, |--> "lgCMatrix" ## no 'x' --> patter*n* matrix: (n <- sparseMatrix(i=1:6, j=rev(2:7)))# -> ngCMatrix ## an empty sparse matrix: (e <- sparseMatrix(dims = c(4,6), i={}, j={})) ## a symmetric one: (sy <- sparseMatrix(i= c(2,4,3:5), j= c(4,7:5,5), x = 1:5, dims = c(7,7), symmetric=TRUE)) stopifnot(isSymmetric(sy), identical(sy, ## switch i <-> j {and transpose } t( sparseMatrix(j= c(2,4,3:5), i= c(4,7:5,5), x = 1:5, dims = c(7,7), symmetric=TRUE)))) ## rsparsematrix() calls sparseMatrix() : M1 <- rsparsematrix(1000, 20, nnz = 200) summary(M1) ## pointers example in converting from other sparse matrix representations. if(requireNamespace("SparseM") && packageVersion("SparseM") >= "0.87" && nzchar(dfil <- system.file("extdata", "rua_32_ax.rua", package = "SparseM"))) { X <- SparseM::model.matrix(SparseM::read.matrix.hb(dfil)) XX <- sparseMatrix(j = X@ja, p = X@ia - 1L, x = X@ra, dims = X@dimension) validObject(XX) ## Alternatively, and even more user friendly : X. <- as(X, "Matrix") # or also X2 <- as(X, "sparseMatrix") stopifnot(identical(XX, X.), identical(X., X2)) }## simple example i <- c(1,3:8); j <- c(2,9,6:10); x <- 7 * (1:7) (A <- sparseMatrix(i, j, x = x)) ## 8 x 10 "dgCMatrix" summary(A) str(A) # note that *internally* 0-based row indices are used (sA <- sparseMatrix(i, j, x = x, symmetric = TRUE)) ## 10 x 10 "dsCMatrix" (tA <- sparseMatrix(i, j, x = x, triangular= TRUE)) ## 10 x 10 "dtCMatrix" stopifnot( all(sA == tA + t(tA)) , identical(sA, as(tA + t(tA), "symmetricMatrix"))) ## dims can be larger than the maximum row or column indices (AA <- sparseMatrix(c(1,3:8), c(2,9,6:10), x = 7 * (1:7), dims = c(10,20))) summary(AA) ## i, j and x can be in an arbitrary order, as long as they are consistent set.seed(1); (perm <- sample(1:7)) (A1 <- sparseMatrix(i[perm], j[perm], x = x[perm])) stopifnot(identical(A, A1)) ## The slots are 0-index based, so try( sparseMatrix(i=A@i, p=A@p, x= seq_along(A@x)) ) ## fails and you should say so: 1-indexing is FALSE: sparseMatrix(i=A@i, p=A@p, x= seq_along(A@x), index1 = FALSE) ## the (i,j) pairs can be repeated, in which case the x's are summed (args <- data.frame(i = c(i, 1), j = c(j, 2), x = c(x, 2))) (Aa <- do.call(sparseMatrix, args)) ## explicitly ask for elimination of such duplicates, so ## that the last one is used: (A. <- do.call(sparseMatrix, c(args, list(use.last.ij = TRUE)))) stopifnot(Aa[1,2] == 9, # 2+7 == 9 A.[1,2] == 2) # 2 was *after* 7 ## for a pattern matrix, of course there is no "summing": (nA <- do.call(sparseMatrix, args[c("i","j")])) dn <- list(LETTERS[1:3], letters[1:5]) ## pointer vectors can be used, and the (i,x) slots are sorted if necessary: m <- sparseMatrix(i = c(3,1, 3:2, 2:1), p= c(0:2, 4,4,6), x = 1:6, dimnames = dn) m str(m) stopifnot(identical(dimnames(m), dn)) sparseMatrix(x = 2.72, i=1:3, j=2:4) # recycling x sparseMatrix(x = TRUE, i=1:3, j=2:4) # recycling x, |--> "lgCMatrix" ## no 'x' --> patter*n* matrix: (n <- sparseMatrix(i=1:6, j=rev(2:7)))# -> ngCMatrix ## an empty sparse matrix: (e <- sparseMatrix(dims = c(4,6), i={}, j={})) ## a symmetric one: (sy <- sparseMatrix(i= c(2,4,3:5), j= c(4,7:5,5), x = 1:5, dims = c(7,7), symmetric=TRUE)) stopifnot(isSymmetric(sy), identical(sy, ## switch i <-> j {and transpose } t( sparseMatrix(j= c(2,4,3:5), i= c(4,7:5,5), x = 1:5, dims = c(7,7), symmetric=TRUE)))) ## rsparsematrix() calls sparseMatrix() : M1 <- rsparsematrix(1000, 20, nnz = 200) summary(M1) ## pointers example in converting from other sparse matrix representations. if(requireNamespace("SparseM") && packageVersion("SparseM") >= "0.87" && nzchar(dfil <- system.file("extdata", "rua_32_ax.rua", package = "SparseM"))) { X <- SparseM::model.matrix(SparseM::read.matrix.hb(dfil)) XX <- sparseMatrix(j = X@ja, p = X@ia - 1L, x = X@ra, dims = X@dimension) validObject(XX) ## Alternatively, and even more user friendly : X. <- as(X, "Matrix") # or also X2 <- as(X, "sparseMatrix") stopifnot(identical(XX, X.), identical(X., X2)) }
sparseMatrix is a virtual subclass of
Matrix representing sparse format matrices.
Formally, a sparse format is a storage format in which the space
required to represent an matrix with
nonzero entries is .
Dim, Dimnames
inherited from virtual superclass
Matrix.
Package Matrix defines two virtual subclasses of
denseMatrix: unpackedMatrix and
packedMatrix. These correspond to the
conventional rectangular and packed storage formats used by LAPACK:
https://netlib.org/lapack/lug/node121.html. See those help
topics for implementation details and (recursively) further
subclasses.
“Complementary” class denseMatrix
representing dense (meaning not sparse) format matrices.
Function sparseMatrix, a widely used (but not the only)
constructor for sparseMatrix objects. Other options for
construction, not including explicit coercion:
Matrix(sparse = TRUE),
xtabs(sparse = TRUE),
sparse.model.matrix(), ...
showClass("sparseMatrix") ## and look at the help() of its subclasses M <- Matrix(0, 10000, 100) M[1,1] <- M[2,3] <- 3.14 M ## show(.) method suppresses printing of the majority of rows data(CAex, package = "Matrix") dim(CAex) # 72 x 72 matrix determinant(CAex) # works via sparse lu(.) ## factor -> t( <sparse design matrix> ) : (fact <- gl(5, 3, 30, labels = LETTERS[1:5])) (Xt <- as(fact, "sparseMatrix")) # indicator rows ## missing values --> all-0 columns: f.mis <- fact i.mis <- c(3:5, 17) is.na(f.mis) <- i.mis Xt != (X. <- as(f.mis, "sparseMatrix")) # differ only in columns 3:5,17 stopifnot(all(X.[,i.mis] == 0), all(Xt[,-i.mis] == X.[,-i.mis]))showClass("sparseMatrix") ## and look at the help() of its subclasses M <- Matrix(0, 10000, 100) M[1,1] <- M[2,3] <- 3.14 M ## show(.) method suppresses printing of the majority of rows data(CAex, package = "Matrix") dim(CAex) # 72 x 72 matrix determinant(CAex) # works via sparse lu(.) ## factor -> t( <sparse design matrix> ) : (fact <- gl(5, 3, 30, labels = LETTERS[1:5])) (Xt <- as(fact, "sparseMatrix")) # indicator rows ## missing values --> all-0 columns: f.mis <- fact i.mis <- c(3:5, 17) is.na(f.mis) <- i.mis Xt != (X. <- as(f.mis, "sparseMatrix")) # differ only in columns 3:5,17 stopifnot(all(X.[,i.mis] == 0), all(Xt[,-i.mis] == X.[,-i.mis]))
sparseQR is the class of sparse, row- and column-pivoted
QR factorizations of ()
real matrices, having the general form
or (equivalently)
where
and are permutation matrices,
is an orthogonal matrix
( contains the first column vectors)
equal to the product of Householder matrices , and
is an upper trapezoidal matrix
( contains the first row vectors and is
upper triangular).
The method for qr.Q does not return but rather the
(also orthogonal) product . This behaviour
is algebraically consistent with the base implementation
(see qr), which can be seen by noting that
qr.default in base does not pivot rows, constraining
to be an identity matrix. It follows that
qr.Q(qr.default(x)) also returns .
Similarly, the methods for qr.qy and qr.qty multiply
on the left by and
rather than and .
It is wrong to expect the values of qr.Q (or qr.R,
qr.qy, qr.qty) computed from “equivalent”
sparse and dense factorizations
(say, qr(x) and qr(as(x, "matrix")) for x
of class dgCMatrix) to compare equal.
The underlying factorization algorithms are quite different,
notably as they employ different pivoting strategies,
and in general the factorization is not unique even for fixed
and .
On the other hand, the values of qr.X, qr.coef,
qr.fitted, and qr.resid are well-defined, and
in those cases the sparse and dense computations should
compare equal (within some tolerance).
The method for qr.R is a simple wrapper around qrR,
but not back-permuting by default and never giving row names.
It did not support backPermute = TRUE until Matrix
1.6-0, hence code needing the back-permuted result should
call qrR if Matrix >= 1.6-0 is not known.
Dim, Dimnames
inherited from virtual class
MatrixFactorization.
betaa numeric vector of length Dim[2],
used to construct Householder matrices; see V below.
Van object of class dgCMatrix
with Dim[2] columns. The number of rows nrow(V)
is at least Dim[1] and at most Dim[1]+Dim[2].
V is lower trapezoidal, and its column vectors generate the
Householder matrices that compose the orthogonal
factor. Specifically, is constructed as
diag(Dim[1]) - beta[j] * tcrossprod(V[, j]).
Ran object of class dgCMatrix
with nrow(V) rows and Dim[2] columns.
R is the upper trapezoidal factor.
p, q
0-based integer vectors of length
nrow(V) and Dim[2], respectively,
specifying the permutations applied to the rows and columns of
the factorized matrix. q of length 0 is valid and
equivalent to the identity permutation, implying no column pivoting.
Using R syntax, the matrix
is precisely A[p+1, q+1]
(A[p+1, ] when q has length 0).
Class QR, directly.
Class MatrixFactorization, by class
QR, distance 2.
Objects can be generated directly by calls of the form
new("sparseQR", ...), but they are more typically obtained
as the value of qr(x) for x inheriting from
sparseMatrix (often dgCMatrix).
determinantsignature(x = "sparseQR", logarithm = "logical"):
computes the determinant of the factorized matrix
or its logarithm.
expand1signature(x = "sparseQR"):
see expand1-methods.
expand2signature(x = "sparseQR"):
see expand2-methods.
qr.Qsignature(qr = "sparseQR"):
returns as a dgeMatrix either
or ,
depending on optional argument complete. The default
is FALSE, indicating .
qr.Rsignature(qr = "sparseQR"):
qrR returns , ,
, or ,
depending on optional arguments complete and
backPermute. The default in both cases is FALSE,
indicating , for compatibility with base.
The class of the result in that case is
dtCMatrix. In the other three cases,
it is dgCMatrix.
qr.Xsignature(qr = "sparseQR"):
returns as a dgeMatrix,
by default. If and optional argument
ncol is greater than , then the result
is augmented with , where
is composed of columns through
ncol of the identity matrix.
qr.coefsignature(qr = "sparseQR", y = .):
returns as a dgeMatrix or vector
the result of multiplying y on the left by
.
qr.fittedsignature(qr = "sparseQR", y = .):
returns as a dgeMatrix or vector
the result of multiplying y on the left by
.
qr.residsignature(qr = "sparseQR", y = .):
returns as a dgeMatrix or vector
the result of multiplying y on the left by
.
qr.qtysignature(qr = "sparseQR", y = .):
returns as a dgeMatrix or vector
the result of multiplying y on the left by
.
qr.qysignature(qr = "sparseQR", y = .):
returns as a dgeMatrix or vector
the result of multiplying y on the left by
.
solvesignature(a = "sparseQR", b = .):
see solve-methods.
Davis, T. A. (2006). Direct methods for sparse linear systems. Society for Industrial and Applied Mathematics. doi:10.1137/1.9780898718881
Golub, G. H., & Van Loan, C. F. (2013). Matrix computations (4th ed.). Johns Hopkins University Press. doi:10.56021/9781421407944
Class dgCMatrix.
Generic function qr from base,
whose default method qr.default “defines”
the S3 class qr of dense QR factorizations.
qr-methods for methods defined in Matrix.
Generic functions expand1 and expand2.
The many auxiliary functions for QR factorizations:
qr.Q, qr.R, qr.X,
qr.coef, qr.fitted, qr.resid,
qr.qty, qr.qy, and qr.solve.
showClass("sparseQR") set.seed(2) m <- 300L n <- 60L A <- rsparsematrix(m, n, 0.05) ## With dimnames, to see that they are propagated : dimnames(A) <- dn <- list(paste0("r", seq_len(m)), paste0("c", seq_len(n))) (qr.A <- qr(A)) str(e.qr.A <- expand2(qr.A, complete = FALSE), max.level = 2L) str(E.qr.A <- expand2(qr.A, complete = TRUE), max.level = 2L) t(sapply(e.qr.A, dim)) t(sapply(E.qr.A, dim)) ## Horribly inefficient, but instructive : slowQ <- function(V, beta) { d <- dim(V) Q <- diag(d[1L]) if(d[2L] > 0L) { for(j in d[2L]:1L) { cat(j, "\n", sep = "") Q <- Q - (beta[j] * tcrossprod(V[, j])) %*% Q } } Q } ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) ## A ~ P1' Q R P2' ~ P1' Q1 R1 P2' in floating point stopifnot(exprs = { identical(names(e.qr.A), c("P1.", "Q1", "R1", "P2.")) identical(names(E.qr.A), c("P1.", "Q" , "R" , "P2.")) identical(e.qr.A[["P1."]], new("pMatrix", Dim = c(m, m), Dimnames = c(dn[1L], list(NULL)), margin = 1L, perm = invertPerm(qr.A@p, 0L, 1L))) identical(e.qr.A[["P2."]], new("pMatrix", Dim = c(n, n), Dimnames = c(list(NULL), dn[2L]), margin = 2L, perm = invertPerm(qr.A@q, 0L, 1L))) identical(e.qr.A[["R1"]], triu(E.qr.A[["R"]][seq_len(n), ])) identical(e.qr.A[["Q1"]], E.qr.A[["Q"]][, seq_len(n)] ) identical(E.qr.A[["R"]], qr.A@R) ## ae1(E.qr.A[["Q"]], slowQ(qr.A@V, qr.A@beta)) ae1(crossprod(E.qr.A[["Q"]]), diag(m)) ae1(A, with(e.qr.A, P1. %*% Q1 %*% R1 %*% P2.)) ae1(A, with(E.qr.A, P1. %*% Q %*% R %*% P2.)) ae2(A.perm <- A[qr.A@p + 1L, qr.A@q + 1L], with(e.qr.A, Q1 %*% R1)) ae2(A.perm , with(E.qr.A, Q %*% R )) }) ## More identities b <- rnorm(m) stopifnot(exprs = { ae1(qrX <- qr.X (qr.A ), A) ae2(qrQ <- qr.Q (qr.A ), with(e.qr.A, P1. %*% Q1)) ae2( qr.R (qr.A ), with(e.qr.A, R1)) ae2(qrc <- qr.coef (qr.A, b), with(e.qr.A, solve(R1 %*% P2., t(qrQ)) %*% b)) ae2(qrf <- qr.fitted(qr.A, b), with(e.qr.A, tcrossprod(qrQ) %*% b)) ae2(qrr <- qr.resid (qr.A, b), b - qrf) ae2(qrq <- qr.qy (qr.A, b), with(E.qr.A, P1. %*% Q %*% b)) ae2(qr.qty(qr.A, qrq), b) }) ## Sparse and dense computations should agree here qr.Am <- qr(as(A, "matrix")) # <=> qr.default(A) stopifnot(exprs = { ae2(qrX, qr.X (qr.Am )) ae2(qrc, qr.coef (qr.Am, b)) ae2(qrf, qr.fitted(qr.Am, b)) ae2(qrr, qr.resid (qr.Am, b)) })showClass("sparseQR") set.seed(2) m <- 300L n <- 60L A <- rsparsematrix(m, n, 0.05) ## With dimnames, to see that they are propagated : dimnames(A) <- dn <- list(paste0("r", seq_len(m)), paste0("c", seq_len(n))) (qr.A <- qr(A)) str(e.qr.A <- expand2(qr.A, complete = FALSE), max.level = 2L) str(E.qr.A <- expand2(qr.A, complete = TRUE), max.level = 2L) t(sapply(e.qr.A, dim)) t(sapply(E.qr.A, dim)) ## Horribly inefficient, but instructive : slowQ <- function(V, beta) { d <- dim(V) Q <- diag(d[1L]) if(d[2L] > 0L) { for(j in d[2L]:1L) { cat(j, "\n", sep = "") Q <- Q - (beta[j] * tcrossprod(V[, j])) %*% Q } } Q } ae1 <- function(a, b, ...) all.equal(as(a, "matrix"), as(b, "matrix"), ...) ae2 <- function(a, b, ...) ae1(unname(a), unname(b), ...) ## A ~ P1' Q R P2' ~ P1' Q1 R1 P2' in floating point stopifnot(exprs = { identical(names(e.qr.A), c("P1.", "Q1", "R1", "P2.")) identical(names(E.qr.A), c("P1.", "Q" , "R" , "P2.")) identical(e.qr.A[["P1."]], new("pMatrix", Dim = c(m, m), Dimnames = c(dn[1L], list(NULL)), margin = 1L, perm = invertPerm(qr.A@p, 0L, 1L))) identical(e.qr.A[["P2."]], new("pMatrix", Dim = c(n, n), Dimnames = c(list(NULL), dn[2L]), margin = 2L, perm = invertPerm(qr.A@q, 0L, 1L))) identical(e.qr.A[["R1"]], triu(E.qr.A[["R"]][seq_len(n), ])) identical(e.qr.A[["Q1"]], E.qr.A[["Q"]][, seq_len(n)] ) identical(E.qr.A[["R"]], qr.A@R) ## ae1(E.qr.A[["Q"]], slowQ(qr.A@V, qr.A@beta)) ae1(crossprod(E.qr.A[["Q"]]), diag(m)) ae1(A, with(e.qr.A, P1. %*% Q1 %*% R1 %*% P2.)) ae1(A, with(E.qr.A, P1. %*% Q %*% R %*% P2.)) ae2(A.perm <- A[qr.A@p + 1L, qr.A@q + 1L], with(e.qr.A, Q1 %*% R1)) ae2(A.perm , with(E.qr.A, Q %*% R )) }) ## More identities b <- rnorm(m) stopifnot(exprs = { ae1(qrX <- qr.X (qr.A ), A) ae2(qrQ <- qr.Q (qr.A ), with(e.qr.A, P1. %*% Q1)) ae2( qr.R (qr.A ), with(e.qr.A, R1)) ae2(qrc <- qr.coef (qr.A, b), with(e.qr.A, solve(R1 %*% P2., t(qrQ)) %*% b)) ae2(qrf <- qr.fitted(qr.A, b), with(e.qr.A, tcrossprod(qrQ) %*% b)) ae2(qrr <- qr.resid (qr.A, b), b - qrf) ae2(qrq <- qr.qy (qr.A, b), with(E.qr.A, P1. %*% Q %*% b)) ae2(qr.qty(qr.A, qrq), b) }) ## Sparse and dense computations should agree here qr.Am <- qr(as(A, "matrix")) # <=> qr.default(A) stopifnot(exprs = { ae2(qrX, qr.X (qr.Am )) ae2(qrc, qr.coef (qr.Am, b)) ae2(qrf, qr.fitted(qr.Am, b)) ae2(qrr, qr.resid (qr.Am, b)) })
User friendly construction of sparse vectors,
i.e., objects inheriting from class
sparseVector, from indices and values of its
non-zero entries.
sparseVector(x, i, length)sparseVector(x, i, length)
x |
vector of the non zero entries; may be missing in which case a
|
i |
integer vector (of the same length as |
length |
length of the sparse vector. |
zero entries in x are dropped automatically, analogously as
drop0() acts on sparse matrices.
a sparse vector, i.e., inheriting from class
sparseVector.
Martin Maechler
sparseMatrix() constructor for sparse matrices;
the class sparseVector.
str(sv <- sparseVector(x = 1:10, i = sample(999, 10), length=1000)) sx <- c(0,0,3, 3.2, 0,0,0,-3:1,0,0,2,0,0,5,0,0) ss <- as(sx, "sparseVector") stopifnot(identical(ss, sparseVector(x = c(2, -1, -2, 3, 1, -3, 5, 3.2), i = c(15L, 10:9, 3L,12L,8L,18L, 4L), length = 20L))) (ns <- sparseVector(i= c(7, 3, 2), length = 10)) stopifnot(identical(ns, new("nsparseVector", length = 10, i = c(2, 3, 7))))str(sv <- sparseVector(x = 1:10, i = sample(999, 10), length=1000)) sx <- c(0,0,3, 3.2, 0,0,0,-3:1,0,0,2,0,0,5,0,0) ss <- as(sx, "sparseVector") stopifnot(identical(ss, sparseVector(x = c(2, -1, -2, 3, 1, -3, 5, 3.2), i = c(15L, 10:9, 3L,12L,8L,18L, 4L), length = 20L))) (ns <- sparseVector(i= c(7, 3, 2), length = 10)) stopifnot(identical(ns, new("nsparseVector", length = 10, i = c(2, 3, 7))))
Sparse Vector Classes: The virtual mother class
"sparseVector" has the five actual daughter classes
"dsparseVector", "isparseVector",
"lsparseVector", "nsparseVector", and
"zsparseVector", where we've mainly implemented methods for
the d*, l* and n* ones.
length:class "numeric" - the length
of the sparse vector. Note that "numeric" can be
considerably larger than the maximal "integer",
.Machine$integer.max, on purpose.
i:class "numeric" - the (1-based) indices of
the non-zero entries. Must not be NA and strictly
sorted increasingly.
Note that "integer" is “part of” "numeric",
and can (and often will) be used for non-huge sparseVectors.
x:(for all but "nsparseVector"):
the non-zero entries. This is of class "numeric" for class
"dsparseVector", "logical" for class
"lsparseVector", etc.
signature(x = "sparseVector"): simply extracts
the length slot.
signature(object = "sparseVector"): The
show method for sparse vectors prints
“structural” zeroes as "." using the
non-exported prSpVector function which allows further
customization such as replacing "." by " " (blank).
Note that options(max.print) will influence how many
entries of large sparse vectors are printed at all.
signature(x = "sparseVector", mode = "character")
coerces sparse vectors to “regular”, i.e., atomic vectors.
This is the same as as(x, "vector").
..: see coerce below
signature(from = "sparseVector", to = "sparseMatrix"), and
signature(from = "sparseMatrix", to = "sparseVector"),
etc: coercions to and from sparse matrices (sparseMatrix) are
provided and work analogously as in standard R, i.e., a vector is
coerced to a 1-column matrix.
signature(x = "sparseVector", value = "integer")
coerces a sparse vector to a sparse Matrix, i.e., an object
inheriting from sparseMatrix, of the
appropriate dimension.
signature(x = "sparseVector"): as with R's
(package util) head, head(x,n) (for
) is equivalent to x[1:n], but here can be much
more efficient, see the example.
signature(x = "sparseVector"): analogous to
head, see above.
signature(x = "sparseVector"): as
toeplitz(x), produce the
Toeplitz matrix from x, where n = length(x).
signature(x = "sparseVector") repeat x,
with the same argument list (x, times, length.out, each,
...) as the default method for rep().
signature(x = "nsparseVector") and
signature(x = "lsparseVector") return the
indices of the non-zero entries (which is trivial for sparse vectors).
signature(e1 = "sparseVector", e2 = "*"): define
arithmetic, compare and logic operations, (see
Ops).
signature(x = "sparseVector"): define
all the Summary methods.
(x = "sparseVector"), and
(x = "nsparseVector"):
return logical or "nsparseVector" of the same
length as x, indicating if/where x is
NA (or NaN), finite or infinite, entirely
analogously to the corresponding base R functions.
signature(x = "sparseVectors"): typically used for
numeric sparse vector: round() entries
such that (relatively) very small entries become zero exactly.
c.sparseVector() is an S3 method for all
"sparseVector"s, but automatic dispatch only happens for the
first argument, so it is useful also as regular R function, see the
examples.
sparseVector() for friendly construction of sparse
vectors (apart from as(*, "sparseVector")).
getClass("sparseVector") getClass("dsparseVector") sx <- c(0,0,3, 3.2, 0,0,0,-3:1,0,0,2,0,0,5,0,0) (ss <- as(sx, "sparseVector")) ix <- as.integer(round(sx)) (is <- as(ix, "sparseVector")) ## an "isparseVector" (!) (ns <- sparseVector(i= c(7, 3, 2), length = 10)) # "nsparseVector" ## rep() works too: (ri <- rep(is, length.out= 25)) ## Using `dim<-` as in base R : r <- ss dim(r) <- c(4,5) # becomes a sparse Matrix: r ## or coercion (as as.matrix() in base R): as(ss, "Matrix") stopifnot(all(ss == print(as(ss, "CsparseMatrix")))) ## currently has "non-structural" FALSE -- printing as ":" (lis <- is & FALSE) (nn <- is[is == 0]) # all "structural" FALSE ## NA-case sN <- sx; sN[4] <- NA (svN <- as(sN, "sparseVector")) v <- as(c(0,0,3, 3.2, rep(0,9),-3,0,-1, rep(0,20),5,0), "sparseVector") v <- rep(rep(v, 50), 5000) set.seed(1); v[sample(v@i, 1e6)] <- 0 str(v) system.time(for(i in 1:4) hv <- head(v, 1e6)) ## user system elapsed ## 0.033 0.000 0.032 system.time(for(i in 1:4) h2 <- v[1:1e6]) ## user system elapsed ## 1.317 0.000 1.319 stopifnot(identical(hv, h2), identical(is | FALSE, is != 0), validObject(svN), validObject(lis), as.logical(is.na(svN[4])), identical(is^2 > 0, is & TRUE), all(!lis), !any(lis), length(nn@i) == 0, !any(nn), all(!nn), sum(lis) == 0, !prod(lis), range(lis) == c(0,0)) ## create and use the t(.) method: t(x20 <- sparseVector(c(9,3:1), i=c(1:2,4,7), length=20)) (T20 <- toeplitz(x20)) stopifnot(is(T20, "symmetricMatrix"), is(T20, "sparseMatrix"), identical(unname(as.matrix(T20)), toeplitz(as.vector(x20)))) ## c() method for "sparseVector" - also available as regular function (c1 <- c(x20, 0,0,0, -10*x20)) (c2 <- c(ns, is, FALSE)) (c3 <- c(ns, !ns, TRUE, NA, FALSE)) (c4 <- c(ns, rev(ns))) ## here, c() would produce a list {not dispatching to c.sparseVector()} (c5 <- c.sparseVector(0,0, x20)) ## checking (consistency) .v <- as.vector .s <- function(v) as(v, "sparseVector") stopifnot(exprs = { all.equal(c1, .s(c(.v(x20), 0,0,0, -10*.v(x20))), tol = 0) all.equal(c2, .s(c(.v(ns), .v(is), FALSE)), tol = 0) all.equal(c3, .s(c(.v(ns), !.v(ns), TRUE, NA, FALSE)), tol = 0) all.equal(c4, .s(c(.v(ns), rev(.v(ns)))), tol = 0, check.class = FALSE) all.equal(c5, .s(c(0,0, .v(x20))), tol = 0) })getClass("sparseVector") getClass("dsparseVector") sx <- c(0,0,3, 3.2, 0,0,0,-3:1,0,0,2,0,0,5,0,0) (ss <- as(sx, "sparseVector")) ix <- as.integer(round(sx)) (is <- as(ix, "sparseVector")) ## an "isparseVector" (!) (ns <- sparseVector(i= c(7, 3, 2), length = 10)) # "nsparseVector" ## rep() works too: (ri <- rep(is, length.out= 25)) ## Using `dim<-` as in base R : r <- ss dim(r) <- c(4,5) # becomes a sparse Matrix: r ## or coercion (as as.matrix() in base R): as(ss, "Matrix") stopifnot(all(ss == print(as(ss, "CsparseMatrix")))) ## currently has "non-structural" FALSE -- printing as ":" (lis <- is & FALSE) (nn <- is[is == 0]) # all "structural" FALSE ## NA-case sN <- sx; sN[4] <- NA (svN <- as(sN, "sparseVector")) v <- as(c(0,0,3, 3.2, rep(0,9),-3,0,-1, rep(0,20),5,0), "sparseVector") v <- rep(rep(v, 50), 5000) set.seed(1); v[sample(v@i, 1e6)] <- 0 str(v) system.time(for(i in 1:4) hv <- head(v, 1e6)) ## user system elapsed ## 0.033 0.000 0.032 system.time(for(i in 1:4) h2 <- v[1:1e6]) ## user system elapsed ## 1.317 0.000 1.319 stopifnot(identical(hv, h2), identical(is | FALSE, is != 0), validObject(svN), validObject(lis), as.logical(is.na(svN[4])), identical(is^2 > 0, is & TRUE), all(!lis), !any(lis), length(nn@i) == 0, !any(nn), all(!nn), sum(lis) == 0, !prod(lis), range(lis) == c(0,0)) ## create and use the t(.) method: t(x20 <- sparseVector(c(9,3:1), i=c(1:2,4,7), length=20)) (T20 <- toeplitz(x20)) stopifnot(is(T20, "symmetricMatrix"), is(T20, "sparseMatrix"), identical(unname(as.matrix(T20)), toeplitz(as.vector(x20)))) ## c() method for "sparseVector" - also available as regular function (c1 <- c(x20, 0,0,0, -10*x20)) (c2 <- c(ns, is, FALSE)) (c3 <- c(ns, !ns, TRUE, NA, FALSE)) (c4 <- c(ns, rev(ns))) ## here, c() would produce a list {not dispatching to c.sparseVector()} (c5 <- c.sparseVector(0,0, x20)) ## checking (consistency) .v <- as.vector .s <- function(v) as(v, "sparseVector") stopifnot(exprs = { all.equal(c1, .s(c(.v(x20), 0,0,0, -10*.v(x20))), tol = 0) all.equal(c2, .s(c(.v(ns), .v(is), FALSE)), tol = 0) all.equal(c3, .s(c(.v(ns), !.v(ns), TRUE, NA, FALSE)), tol = 0) all.equal(c4, .s(c(.v(ns), rev(.v(ns)))), tol = 0, check.class = FALSE) all.equal(c5, .s(c(0,0, .v(x20))), tol = 0) })
User friendly construction of a sparse matrix (inheriting from class
TsparseMatrix) from the triplet representation.
This is much less flexible than sparseMatrix() and hence
somewhat deprecated.
spMatrix(nrow, ncol, i = integer(0L), j = integer(0L), x = double(0L))spMatrix(nrow, ncol, i = integer(0L), j = integer(0L), x = double(0L))
nrow, ncol
|
integers specifying the desired number of rows and columns. |
i, j
|
integer vectors of the same length specifying the locations
of the non-zero (or non- |
x |
atomic vector of the same length as |
A sparse matrix in triplet form, as an R object inheriting from both
TsparseMatrix and
generalMatrix.
The matrix will have
M[i[k], j[k]] == x[k], for , where
n = length(i) and
M[ i', j' ] == 0 for all other pairs .
Matrix(*, sparse=TRUE) for the more usual
constructor of such matrices. Then, sparseMatrix
is more general and flexible than spMatrix() and by default
returns a CsparseMatrix which is often slightly
more desirable. Further, bdiag and
Diagonal for (block-)diagonal matrix constructors.
Consider TsparseMatrix and similar class
definition help files.
## simple example A <- spMatrix(10,20, i = c(1,3:8), j = c(2,9,6:10), x = 7 * (1:7)) A # a "dgTMatrix" summary(A) str(A) # note that *internally* 0-based indices (i,j) are used L <- spMatrix(9, 30, i = rep(1:9, 3), 1:27, (1:27) %% 4 != 1) L # an "lgTMatrix" ## A simplified predecessor of Matrix' rsparsematrix() function : rSpMatrix <- function(nrow, ncol, nnz, rand.x = function(n) round(rnorm(nnz), 2)) { ## Purpose: random sparse matrix ## -------------------------------------------------------------- ## Arguments: (nrow,ncol): dimension ## nnz : number of non-zero entries ## rand.x: random number generator for 'x' slot ## -------------------------------------------------------------- ## Author: Martin Maechler, Date: 14.-16. May 2007 stopifnot((nnz <- as.integer(nnz)) >= 0, nrow >= 0, ncol >= 0, nnz <= nrow * ncol) spMatrix(nrow, ncol, i = sample(nrow, nnz, replace = TRUE), j = sample(ncol, nnz, replace = TRUE), x = rand.x(nnz)) } M1 <- rSpMatrix(100000, 20, nnz = 200) summary(M1)## simple example A <- spMatrix(10,20, i = c(1,3:8), j = c(2,9,6:10), x = 7 * (1:7)) A # a "dgTMatrix" summary(A) str(A) # note that *internally* 0-based indices (i,j) are used L <- spMatrix(9, 30, i = rep(1:9, 3), 1:27, (1:27) %% 4 != 1) L # an "lgTMatrix" ## A simplified predecessor of Matrix' rsparsematrix() function : rSpMatrix <- function(nrow, ncol, nnz, rand.x = function(n) round(rnorm(nnz), 2)) { ## Purpose: random sparse matrix ## -------------------------------------------------------------- ## Arguments: (nrow,ncol): dimension ## nnz : number of non-zero entries ## rand.x: random number generator for 'x' slot ## -------------------------------------------------------------- ## Author: Martin Maechler, Date: 14.-16. May 2007 stopifnot((nnz <- as.integer(nnz)) >= 0, nrow >= 0, ncol >= 0, nnz <= nrow * ncol) spMatrix(nrow, ncol, i = sample(nrow, nnz, replace = TRUE), j = sample(ncol, nnz, replace = TRUE), x = rand.x(nnz)) } M1 <- rSpMatrix(100000, 20, nnz = 200) summary(M1)
Methods for "[<-", i.e., extraction or subsetting mostly of
matrices, in package Matrix.
Note: Contrary to standard matrix assignment in
base R, in x[..] <- val it is typically an error (see
stop) when the type or class of
val would require the class of x to be changed, e.g.,
when x is logical, say "lsparseMatrix", and val
is numeric.
In other cases, e.g., when x is a "nsparseMatrix" and
val is not TRUE or FALSE, a warning is signalled,
and val is “interpreted” as logical, and
(logical) NA is interpreted as TRUE.
There are many many more than these:
is currently a simple fallback method implementation which ensures “readable” error messages.
currently gives an error
...
...
...
[-methods for subsetting "Matrix" objects; the
index class;
Extract about the standard subset assignment (and extraction).
set.seed(101) (a <- m <- Matrix(round(rnorm(7*4),2), nrow = 7)) a[] <- 2.2 # <<- replaces **every** entry a ## as do these: a[,] <- 3 ; a[TRUE,] <- 4 m[2, 3] <- 3.14 # simple number m[3, 3:4]<- 3:4 # simple numeric of length 2 ## sub matrix assignment: m[-(4:7), 3:4] <- cbind(1,2:4) #-> upper right corner of 'm' m[3:5, 2:3] <- 0 m[6:7, 1:2] <- Diagonal(2) m ## rows or columns only: m[1,] <- 10 m[,2] <- 1:7 m[-(1:6), ] <- 3:0 # not the first 6 rows, i.e. only the 7th as(m, "sparseMatrix")set.seed(101) (a <- m <- Matrix(round(rnorm(7*4),2), nrow = 7)) a[] <- 2.2 # <<- replaces **every** entry a ## as do these: a[,] <- 3 ; a[TRUE,] <- 4 m[2, 3] <- 3.14 # simple number m[3, 3:4]<- 3:4 # simple numeric of length 2 ## sub matrix assignment: m[-(4:7), 3:4] <- cbind(1,2:4) #-> upper right corner of 'm' m[3:5, 2:3] <- 0 m[6:7, 1:2] <- Diagonal(2) m ## rows or columns only: m[1,] <- 10 m[,2] <- 1:7 m[-(1:6), ] <- 3:0 # not the first 6 rows, i.e. only the 7th as(m, "sparseMatrix")
Methods for "[", i.e., extraction or subsetting mostly of
matrices, in package Matrix.
There are more than these:
...
...
...
...
...
...
[<–methods for subassignment to "Matrix"
objects.
Extract about the standard extraction.
str(m <- Matrix(round(rnorm(7*4),2), nrow = 7)) stopifnot(identical(m, m[])) m[2, 3] # simple number m[2, 3:4] # simple numeric of length 2 m[2, 3:4, drop=FALSE] # sub matrix of class 'dgeMatrix' ## rows or columns only: m[1,] # first row, as simple numeric vector m[,1:2] # sub matrix of first two columns showMethods("[", inherited = FALSE)str(m <- Matrix(round(rnorm(7*4),2), nrow = 7)) stopifnot(identical(m, m[])) m[2, 3] # simple number m[2, 3:4] # simple numeric of length 2 m[2, 3:4, drop=FALSE] # sub matrix of class 'dgeMatrix' ## rows or columns only: m[1,] # first row, as simple numeric vector m[,1:2] # sub matrix of first two columns showMethods("[", inherited = FALSE)
TODO.
Summary(x, ..., na.rm = FALSE)Summary(x, ..., na.rm = FALSE)
x |
. |
... |
. |
na.rm |
. |
symmetricMatrix is a virtual subclass of
Matrix representing Hermitian or symmetric
matrices. Objects inheriting from symmetricMatrix have
symmetric dimension names.
Diminherited from virtual superclass
Matrix. Dim[1] and Dim[2] must
be equal.
Dimnamesinherited from virtual superclass
Matrix. The actual dimension names of
objects x are obtained by dimnames(x), not by
x@Dimnames. The method for dimnames symmetrizes the
Dimnames slot, which can be asymmetric, and returns the
result; see dimnames-methods. The validity method
for class symmetricMatrix may be changed in a future
version of Matrix to require a symmetric Dimnames
slot, so that the actual dimension names of objects x can
be obtained directly as x@Dimnames.
factorsa list of
MatrixFactorization objects caching
factorizations of the represented matrix. It is updated
“automagically” by methods for generic functions that
compute matrix factorizations, such as lu.
The caching mechanism is not idiomatic as it circumvents R's
usual copy semantics; it may be deprecated in a future version of
Matrix, hence code intended to be forwards compatible will
not access the factors slot.
uplo.
All direct, nonvirtual subclasses of symmetricMatrix defined in
package Matrix have an additional slot:
uploa character string, either "U" or
"L". "U" indicates that only the upper triangular
entries of the represented matrix are stored. "L"
indicates that only the lower triangular entries of the
represented matrix are stored.
The direct, nonvirtual subclasses of symmetricMatrix defined in
package Matrix are listed below with links to virtual
superclasses defining their data type and storage format.
| Nonvirtual subclass | Data type | Storage format |
nsyMatrix |
nMatrix |
unpackedMatrix
|
lsyMatrix |
lMatrix |
unpackedMatrix
|
isyMatrix |
iMatrix |
unpackedMatrix
|
dsyMatrix |
dMatrix |
unpackedMatrix
|
zsyMatrix |
zMatrix |
unpackedMatrix
|
nspMatrix |
nMatrix |
packedMatrix
|
lspMatrix |
lMatrix |
packedMatrix
|
ispMatrix |
iMatrix |
packedMatrix
|
dspMatrix |
dMatrix |
packedMatrix
|
zspMatrix |
zMatrix |
packedMatrix
|
ngCMatrix |
nMatrix |
CsparseMatrix
|
lsCMatrix |
lMatrix |
CsparseMatrix
|
isCMatrix |
iMatrix |
CsparseMatrix
|
dsCMatrix |
dMatrix |
CsparseMatrix
|
zsCMatrix |
zMatrix |
CsparseMatrix
|
nsRMatrix |
nMatrix |
RsparseMatrix
|
lsRMatrix |
lMatrix |
RsparseMatrix
|
isRMatrix |
iMatrix |
RsparseMatrix
|
dsRMatrix |
dMatrix |
RsparseMatrix
|
zsRMatrix |
zMatrix |
RsparseMatrix
|
nsTMatrix |
nMatrix |
TsparseMatrix
|
lsTMatrix |
lMatrix |
TsparseMatrix
|
isTMatrix |
iMatrix |
TsparseMatrix
|
dsTMatrix |
dMatrix |
TsparseMatrix
|
zsTMatrix |
zMatrix |
TsparseMatrix
|
The subclasses of iMatrix and zMatrix were not defined
until Matrix version 1.8-0.
Related classes
generalMatrix,
posdefMatrix,
triangularMatrix,
diagonalMatrix, and
indexMatrix representing
general (unstructured, possibly nonsquare), positive semidefinite,
triangular, diagonal, and index matrices. Generic function
isSymmetric for testing for testing if a matrix
is (possibly approximately) Hermitian or symmetric. Generic
function forceSymmetric for inducing Hermitian
or symmetric structure. Generic function
symmpart for getting the Hermitian or symmetric
part of a square matrix. Generic function
skewpart for getting the skew-Hermitian or
skew-symmetric part of a square matrix. Generic function
BunchKaufman for Bunch-Kaufman factorization of
Hermitian or symmetric matrices.
## An example about the symmetric Dimnames: sy <- sparseMatrix(i= c(2,4,3:5), j= c(4,7:5,5), x = 1:5, dims = c(7,7), symmetric=TRUE, dimnames = list(NULL, letters[1:7])) sy # shows symmetrical dimnames sy@Dimnames # internally only one part is stored dimnames(sy) # both parts - as sy *is* symmetrical showClass("symmetricMatrix") ## The names of direct subclasses: scl <- getClass("symmetricMatrix")@subclasses directly <- sapply(lapply(scl, slot, "by"), length) == 0 names(scl)[directly] ## Methods -- applicaple to all subclasses above: showMethods(classes = "symmetricMatrix")## An example about the symmetric Dimnames: sy <- sparseMatrix(i= c(2,4,3:5), j= c(4,7:5,5), x = 1:5, dims = c(7,7), symmetric=TRUE, dimnames = list(NULL, letters[1:7])) sy # shows symmetrical dimnames sy@Dimnames # internally only one part is stored dimnames(sy) # both parts - as sy *is* symmetrical showClass("symmetricMatrix") ## The names of direct subclasses: scl <- getClass("symmetricMatrix")@subclasses directly <- sapply(lapply(scl, slot, "by"), length) == 0 names(scl)[directly] ## Methods -- applicaple to all subclasses above: showMethods(classes = "symmetricMatrix")
Compute the symmetric (Hermitian) and skew-symmetric (skew-Hermitian)
parts of a square matrix x, defined as (x + op(x))/2 and
(x - op(x))/2, respectively, where op denotes matrix
transpose (conjugate transpose).
symmpart(x, ...) skewpart(x, ...) ## S4 method for signature 'denseMatrix' symmpart(x, uplo = "U", trans = "C", ...) ## S4 method for signature 'CsparseMatrix' symmpart(x, uplo = "U", trans = "C", ...) ## S4 method for signature 'RsparseMatrix' symmpart(x, uplo = "U", trans = "C", ...) ## S4 method for signature 'TsparseMatrix' symmpart(x, uplo = "U", trans = "C", ...) ## S4 method for signature 'diagonalMatrix' symmpart(x, trans = "C", ...) ## S4 method for signature 'indMatrix' symmpart(x, ...) ## S4 method for signature 'matrix' symmpart(x, trans = "C", ...) ## S4 method for signature 'denseMatrix' skewpart(x, trans = "C", ...) ## S4 method for signature 'CsparseMatrix' skewpart(x, trans = "C", ...) ## S4 method for signature 'RsparseMatrix' skewpart(x, trans = "C", ...) ## S4 method for signature 'TsparseMatrix' skewpart(x, trans = "C", ...) ## S4 method for signature 'diagonalMatrix' skewpart(x, trans = "C", ...) ## S4 method for signature 'indMatrix' skewpart(x, ...) ## S4 method for signature 'matrix' skewpart(x, trans = "C", ...)symmpart(x, ...) skewpart(x, ...) ## S4 method for signature 'denseMatrix' symmpart(x, uplo = "U", trans = "C", ...) ## S4 method for signature 'CsparseMatrix' symmpart(x, uplo = "U", trans = "C", ...) ## S4 method for signature 'RsparseMatrix' symmpart(x, uplo = "U", trans = "C", ...) ## S4 method for signature 'TsparseMatrix' symmpart(x, uplo = "U", trans = "C", ...) ## S4 method for signature 'diagonalMatrix' symmpart(x, trans = "C", ...) ## S4 method for signature 'indMatrix' symmpart(x, ...) ## S4 method for signature 'matrix' symmpart(x, trans = "C", ...) ## S4 method for signature 'denseMatrix' skewpart(x, trans = "C", ...) ## S4 method for signature 'CsparseMatrix' skewpart(x, trans = "C", ...) ## S4 method for signature 'RsparseMatrix' skewpart(x, trans = "C", ...) ## S4 method for signature 'TsparseMatrix' skewpart(x, trans = "C", ...) ## S4 method for signature 'diagonalMatrix' skewpart(x, trans = "C", ...) ## S4 method for signature 'indMatrix' skewpart(x, ...) ## S4 method for signature 'matrix' skewpart(x, trans = "C", ...)
x |
an R object representing a square matrix. Package
Matrix provides methods for |
uplo |
a character string, |
trans |
a character string, |
... |
optional arguments passed from or to other methods. |
An R object representing a symmetric (Hermitian) or skew-symmetric
(skew-Hermitian) matrix, inheriting from virtual class
Matrix if x does. The dimension names are
the result of symmetrizing dimnames(x) giving precedence to the
column names unless those are NULL and the row names are
non-NULL.
(X <- new("zgeMatrix", Dim = c(3L, 3L), Dimnames = list(A = paste0("a", 1:3), B = paste0("b", 1:3)), x = 0:8 * rep(c(1, -1i), length.out = 9L))) (Xc0 <- symmpart(X)) # Hermitian (Xc1 <- skewpart(X)) # skew-Hermitian (Xt0 <- symmpart(X, trans = "T")) # symmetric (Xt1 <- skewpart(X, trans = "T")) # skew-symmetric stopifnot(isSymmetric(Xc0), isSymmetric(Xc1 * 1i), isSymmetric(Xt0, trans = "T"), isSymmetric(Xt1 * ifelse(upper.tri(Xt1), 1, -1), trans = "T"), all(Xc0 + Xc1 == X), all(Xt0 + Xt1 == X), all(Im(diag(Xc0)) == 0), all(Re(diag(Xc1)) == 0), all(diag(Xt1) == 0i), max(abs(Im(eigen(Xc0)$values))) < 16 * .Machine$double.eps, max(abs(Re(eigen(Xc1)$values))) < 16 * .Machine$double.eps, identical(lapply(list(Xc0, Xc1, Xt0, Xt1), dimnames), rep(list(dimnames(X)[c(2L, 2L)]), 4L)))(X <- new("zgeMatrix", Dim = c(3L, 3L), Dimnames = list(A = paste0("a", 1:3), B = paste0("b", 1:3)), x = 0:8 * rep(c(1, -1i), length.out = 9L))) (Xc0 <- symmpart(X)) # Hermitian (Xc1 <- skewpart(X)) # skew-Hermitian (Xt0 <- symmpart(X, trans = "T")) # symmetric (Xt1 <- skewpart(X, trans = "T")) # skew-symmetric stopifnot(isSymmetric(Xc0), isSymmetric(Xc1 * 1i), isSymmetric(Xt0, trans = "T"), isSymmetric(Xt1 * ifelse(upper.tri(Xt1), 1, -1), trans = "T"), all(Xc0 + Xc1 == X), all(Xt0 + Xt1 == X), all(Im(diag(Xc0)) == 0), all(Re(diag(Xc1)) == 0), all(diag(Xt1) == 0i), max(abs(Im(eigen(Xc0)$values))) < 16 * .Machine$double.eps, max(abs(Re(eigen(Xc1)$values))) < 16 * .Machine$double.eps, identical(lapply(list(Xc0, Xc1, Xt0, Xt1), dimnames), rep(list(dimnames(X)[c(2L, 2L)]), 4L)))
S4 methods defined in package Matrix for S4 generic function
t, generalizing base::t.
## S4 method for signature 'CsparseMatrix' t(x) ## S4 method for signature 'RsparseMatrix' t(x) ## S4 method for signature 'TsparseMatrix' t(x) ## S4 method for signature 'denseMatrix' t(x) ## S4 method for signature 'diagonalMatrix' t(x) ## S4 method for signature 'indMatrix' t(x) ## S4 method for signature 'pMatrix' t(x) ## S4 method for signature 'sparseVector' t(x) .tCRT(x, lazy = TRUE)## S4 method for signature 'CsparseMatrix' t(x) ## S4 method for signature 'RsparseMatrix' t(x) ## S4 method for signature 'TsparseMatrix' t(x) ## S4 method for signature 'denseMatrix' t(x) ## S4 method for signature 'diagonalMatrix' t(x) ## S4 method for signature 'indMatrix' t(x) ## S4 method for signature 'pMatrix' t(x) ## S4 method for signature 'sparseVector' t(x) .tCRT(x, lazy = TRUE)
x |
a |
lazy |
a logical indicating if transposition can change the storage format. |
For consistency, methods for t preserve the storage format of
matrix arguments, even if that is not most efficient. In particular,
if x is a CsparseMatrix object,
then t(x) is a CsparseMatrix object, even though the
RsparseMatrix representation of the transpose
is obtained more cheaply. For “lazy” transposing of compressed
sparse column or row format matrices, interchanging the column and row
formats, use .tCRT.
If x is formally symmetric
(see symmetricMatrix),
then x and t(x) represent the same matrix with opposite
uplo slots, such that one stores only the upper triangle and
the other stores only the lower triangle.
A Matrix object representing the transpose of
x. The class is a superclass of the class of x unless
x is a sparseVector object.
ct and .ctCRT for matrix
conjugate transpose. crossprod for matrix
products involving transposes.
(X <- new("igRMatrix", Dim = c(3L, 5L), Dimnames = list(A = paste0("a", 1:3), B = paste0("b", 1:5)), p = c(0L, 1L, 2L, 5L), j = c(1L, 0L, 0L, 1L, 4L), x = -2:2)) ( tX <- t (X)) # compressed sparse row (.tX <- .tCRT(X)) # compressed sparse column stopifnot(identical(dim(tX), dim(X)[2:1]), identical(dimnames(tX), dimnames(X)[2:1]), identical(X, t ( tX)), identical(X, .tCRT(.tX)), identical( tX, as(.tX, "RsparseMatrix")), identical(.tX, as( tX, "CsparseMatrix")), identical(tX, .tCRT(X, lazy = FALSE))) (S <- crossprod(X)) # formally symmetric (tS <- t(S)) # *output* is identical but stored triangle is different stopifnot(is(S, "dpRMatrix"), all.equal(S, tS, tolerance = 0), S@uplo == "U", tS@uplo == "L", identical(S, t(tS)))(X <- new("igRMatrix", Dim = c(3L, 5L), Dimnames = list(A = paste0("a", 1:3), B = paste0("b", 1:5)), p = c(0L, 1L, 2L, 5L), j = c(1L, 0L, 0L, 1L, 4L), x = -2:2)) ( tX <- t (X)) # compressed sparse row (.tX <- .tCRT(X)) # compressed sparse column stopifnot(identical(dim(tX), dim(X)[2:1]), identical(dimnames(tX), dimnames(X)[2:1]), identical(X, t ( tX)), identical(X, .tCRT(.tX)), identical( tX, as(.tX, "RsparseMatrix")), identical(.tX, as( tX, "CsparseMatrix")), identical(tX, .tCRT(X, lazy = FALSE))) (S <- crossprod(X)) # formally symmetric (tS <- t(S)) # *output* is identical but stored triangle is different stopifnot(is(S, "dpRMatrix"), all.equal(S, tS, tolerance = 0), S@uplo == "U", tS@uplo == "L", identical(S, t(tS)))
S4 methods defined in package Matrix for S4 generic function
toeplitz, generalizing stats::toeplitz.
The S4 generic function definition is obtained from package
methods through the implicitGeneric mechanism.
## S4 method for signature 'sparseVector' toeplitz(x, r = NULL, symmetric = is.null(r), repr = c("C", "R", "T"), giveCsparse, ...)## S4 method for signature 'sparseVector' toeplitz(x, r = NULL, symmetric = is.null(r), repr = c("C", "R", "T"), giveCsparse, ...)
x |
a |
r |
a |
symmetric |
a logical indicating if the return value is formally symmetric. |
repr |
a character string indicating the format of the return value. |
giveCsparse |
deprecated. |
... |
optional arguments not yet used. |
A sparseMatrix object representing the Toeplitz
matrix with first row x or r (x if
symmetric is TRUE or r is NULL) and first
column x. x[1] determines the main diagonal;
r[1] is not used.
x <- new("isparseVector", length = 6L, i = c(2L, 4L, 6L), x = -1L:1L) y <- new("dsparseVector", length = 8L, i = c(2L, 8L), x = c(1.1, 2.2)) (t1s <- toeplitz(x)) (t1g <- toeplitz(x, symmetric = FALSE)) (t2g <- toeplitz(x, y)) stopifnot(is(t1s, "isCMatrix"), is(t1g, "igCMatrix"), is(t2g, "dgCMatrix"), identical(t1g, as(t1s, "generalMatrix")), identical(tril(t2g[, 1L:6L]), as(tril(t1g), "dMatrix")))x <- new("isparseVector", length = 6L, i = c(2L, 4L, 6L), x = -1L:1L) y <- new("dsparseVector", length = 8L, i = c(2L, 8L), x = c(1.1, 2.2)) (t1s <- toeplitz(x)) (t1g <- toeplitz(x, symmetric = FALSE)) (t2g <- toeplitz(x, y)) stopifnot(is(t1s, "isCMatrix"), is(t1g, "igCMatrix"), is(t2g, "dgCMatrix"), identical(t1g, as(t1s, "generalMatrix")), identical(tril(t2g[, 1L:6L]), as(tril(t1g), "dMatrix")))
triangularMatrix is a virtual subclass of
Matrix representing triangular matrices.
Dim, Dimnames
inherited from virtual superclass
Matrix. Dim[1] and Dim[2] must
be equal.
uplo, diag
.
All direct, nonvirtual subclasses of triangularMatrix defined
in package Matrix have two additional slots:
uploa character string, either "U" or
"L". "U" indicates that the represented matrix is
upper triangular and that only the upper triangular entries are
stored. "L" indicates that the represented matrix is lower
triangular and that only the lower triangular entries are stored.
diaga character string, either "N" or
"U". "N" indicates that the diagonal entries of
the represented matrix are stored. "U" indicates that the
represented matrix is unit triangular and that the diagonal
entries, which are all equal to 1, are not stored.
The direct, nonvirtual subclasses of triangularMatrix defined
in package Matrix are listed below with links to virtual
superclasses defining their data type and storage format.
| Nonvirtual subclass | Data type | Storage format |
ntrMatrix |
nMatrix |
unpackedMatrix
|
ltrMatrix |
lMatrix |
unpackedMatrix
|
itrMatrix |
iMatrix |
unpackedMatrix
|
dtrMatrix |
dMatrix |
unpackedMatrix
|
ztrMatrix |
zMatrix |
unpackedMatrix
|
ntpMatrix |
nMatrix |
packedMatrix
|
ltpMatrix |
lMatrix |
packedMatrix
|
itpMatrix |
iMatrix |
packedMatrix
|
dtpMatrix |
dMatrix |
packedMatrix
|
ztpMatrix |
zMatrix |
packedMatrix
|
ntCMatrix |
nMatrix |
CsparseMatrix
|
ltCMatrix |
lMatrix |
CsparseMatrix
|
itCMatrix |
iMatrix |
CsparseMatrix
|
dtCMatrix |
dMatrix |
CsparseMatrix
|
ztCMatrix |
zMatrix |
CsparseMatrix
|
ntRMatrix |
nMatrix |
RsparseMatrix
|
ltRMatrix |
lMatrix |
RsparseMatrix
|
itRMatrix |
iMatrix |
RsparseMatrix
|
dtRMatrix |
dMatrix |
RsparseMatrix
|
ztRMatrix |
zMatrix |
RsparseMatrix
|
ntTMatrix |
nMatrix |
TsparseMatrix
|
ltTMatrix |
lMatrix |
TsparseMatrix
|
itTMatrix |
iMatrix |
TsparseMatrix
|
dtTMatrix |
dMatrix |
TsparseMatrix
|
ztTMatrix |
zMatrix |
TsparseMatrix
|
The subclasses of iMatrix and zMatrix were not defined
until Matrix version 1.8-0.
Related classes
generalMatrix,
symmetricMatrix,
posdefMatrix,
diagonalMatrix, and
indexMatrix representing
general (unstructured, possibly nonsquare), Hermitian or symmetric,
positive semidefinite, diagonal, and index matrices. Generic function
isTriangular for testing for testing if a
matrix is upper or lower triangular. Generic function
forceTriangular for inducing upper or lower
triangular structure. Generic functions band,
triu, and tril for
inducing banded, upper trapezoidal, and lower trapezoidal structure.
showClass("triangularMatrix") ## The names of direct subclasses: scl <- getClass("triangularMatrix")@subclasses directly <- sapply(lapply(scl, slot, "by"), length) == 0 names(scl)[directly] (m <- matrix(c(5, 1, 0, 3), 2)) as(m, "triangularMatrix")showClass("triangularMatrix") ## The names of direct subclasses: scl <- getClass("triangularMatrix")@subclasses directly <- sapply(lapply(scl, slot, "by"), length) == 0 names(scl)[directly] (m <- matrix(c(5, 1, 0, 3), 2)) as(m, "triangularMatrix")
TsparseMatrix is a virtual subclass of
sparseMatrix representing triplet format
matrices. To represent an m-by-n matrix A, this
format stores the positions of m*n or fewer
(often ) entries of A.
Authors of subclasses of TsparseMatrix are free to declare how
this information is used to specify A. See ‘Subclasses’
for subclasses defined in package Matrix.
The triplet format is convenient for reading and writing sparse
matrices but often not amenable to direct computation. Accordingly,
methods for TsparseMatrix defined in package Matrix tend
to work by coercion to and from a more tractable compressed
sparse format. Users can avoid repeated coercions by methods by
coercing sparse matrix operands to either
CsparseMatrix or
RsparseMatrix before computing with them.
Dim, Dimnames
inherited from virtual superclass
Matrix.
i, j
integer vectors of equal length
corresponding to a subset V of the set of entries of
A. Respectively, i and j store the 0-based
row and column indices of the elements of V. Hence, to be
valid, i and j must satisfy 0 <= i < Dim[1]
and 0 <= j < Dim[2]. The common length of i and
j can exceed the size of V, allowing for duplication
of the form i[k1] == i[k2], j[k1] == j[k2],
k1 != k2.
The nonvirtual subclasses of TsparseMatrix defined in package
Matrix are listed below with links to virtual superclasses
defining their data type and structure.
| Nonvirtual subclass | Data type | Structure |
ngTMatrix |
nMatrix |
generalMatrix
|
lgTMatrix |
lMatrix |
generalMatrix
|
igTMatrix |
iMatrix |
generalMatrix
|
dgTMatrix |
dMatrix |
generalMatrix
|
zgTMatrix |
zMatrix |
generalMatrix
|
nsTMatrix |
nMatrix |
symmetricMatrix
|
lsTMatrix |
lMatrix |
symmetricMatrix
|
isTMatrix |
iMatrix |
symmetricMatrix
|
dsTMatrix |
dMatrix |
symmetricMatrix
|
zsTMatrix |
zMatrix |
symmetricMatrix
|
dpTMatrix |
dMatrix |
posdefMatrix
|
zpTMatrix |
zMatrix |
posdefMatrix
|
ntTMatrix |
nMatrix |
triangularMatrix
|
ltTMatrix |
lMatrix |
triangularMatrix
|
itTMatrix |
iMatrix |
triangularMatrix
|
dtTMatrix |
dMatrix |
triangularMatrix
|
ztTMatrix |
zMatrix |
triangularMatrix
|
The subclasses of iMatrix, zMatrix, and
posdefMatrix were not defined until Matrix version 1.8-0.
Classes .gTMatrix represent general (unstructured, possibly
nonsquare) A. Objects have i and j slots
specifying a subset V of the set of entries of A, as
described in ‘Slots’. For ngTMatrix, whose data type is
boolean, the entries in V have value 1, and the entries not in
V have value 0. For other .gTMatrix, the entries in
V have values taken from an additional x slot (a
logical, integer, double, or complex vector), and the entries not in
V have value 0. The i, j, and x slots
have a common length, and the value of A[i[k], j[k]] is the
result of aggregating x[i == i[k] & j == j[k]] by summation
(reduction by | if x is logical, by + otherwise).
Classes .sCMatrix represent Hermitian or symmetric A.
Compared to .gTMatrix, objects have an additional uplo
slot indicating a restriction on V. If uplo="U", then
V contains only upper triangular entries of A. If
uplo="L", then V contains only lower triangular entries
of A. The entries in V have value 1 (nsCMatrix)
or values taken from an x slot (other .sCMatrix). The
entries opposite the main diagonal, namely A[j, i] for all
A[i, j] in V, have value op(A[i, j]), where
op=Conj for Hermitian A and op=identity for
symmetric A. All other entries of A have value 0.
Objects of class zsTMatrix have an additional trans
slot that distinguishes Hermitian and symmetric A, which use
trans="C" and "T", respectively. If trans="C"
and V contains diagonal entries of A, then the imaginary
parts of the corresponding elements of x are not referenced.
(The diagonal entries of Hermitian matrices are real by definition.)
Classes dpTMatrix and zpTMatrix extend dsTMatrix
and zsTMatrix and represent positive semidefinite A.
Positive semidefiniteness of A induces a constraint on the
x slot. However, this constraint is not strictly enforced by
the validity methods, which test only that the diagonal entries of
A are nonnegative (a necessary, not sufficient condition).
For zpTMatrix, only trans="C" is valid.
Classes .tTMatrix represent triangular A. Compared to
.gTMatrix, objects have additional uplo and diag
slots indicating restrictions on V. If uplo="U", then
A is upper triangular and V contains only upper
triangular entries. If uplo="L", then A is lower
triangular and V contains only lower triangular entries. If
diag="U" (instead of "N"), then A is unit
triangular and V contains only strictly upper or lower
triangular entries. The entries in V have value 1
(ntCMatrix) or values taken from an x slot (other
.tCMatrix). With the exception of diagonal entries when
diag="U", which have value 1, entries not in V have
value 0.
“Sister” classes CsparseMatrix and
RsparseMatrix for compressed sparse column and
compressed sparse row format matrices. Functions
aggregateT and asUniqueT for
“canonicalizing” objects inheriting from TsparseMatrix.
showClass("TsparseMatrix") ## or just the subclasses' names names(getClass("TsparseMatrix")@subclasses) T3 <- spMatrix(3,4, i=c(1,3:1), j=c(2,4:2), x=1:4) T3 # only 3 non-zero entries, 5 = 1+4 ! m <- Matrix(0+1:28, nrow = 4) m[-3,c(2,4:5,7)] <- m[ 3, 1:4] <- m[1:3, 6] <- 0 (mT <- as(m, "TsparseMatrix")) str(mT) mT[1,] mT[4, drop = FALSE] stopifnot(identical(mT[lower.tri(mT)], m [lower.tri(m) ])) mT[lower.tri(mT,diag=TRUE)] <- 0 mT ## Triplet representation with repeated (i,j) entries ## *adds* the corresponding x's: T2 <- new("dgTMatrix", i = as.integer(c(1,1,0,3,3)), j = as.integer(c(2,2,4,0,0)), x=10*1:5, Dim=4:5) str(T2) # contains (i,j,x) slots exactly as above, but T2 ## has only three non-zero entries, as for repeated (i,j)'s, ## the corresponding x's are "implicitly" added stopifnot(nnzero(T2) == 3) mm <- Matrix(toeplitz(c(10, 0, 1, 0, 3)), sparse = TRUE) mm # automatically dsCMatrix str(mm) mT <- as(as(mm, "generalMatrix"), "TsparseMatrix") ## Either (symM <- as(mT, "symmetricMatrix")) # dsT (symC <- as(symM, "CsparseMatrix")) # dsC ## or sT <- Matrix(mT, sparse=TRUE, forceCheck=TRUE) # dsT sym2 <- as(symC, "TsparseMatrix") ## --> the same as 'symM', a "dsTMatrix" showClass("dtCMatrix") showClass("dtTMatrix") t1 <- new("dtTMatrix", x= c(3,7), i= 0:1, j=3:2, Dim= as.integer(c(4,4))) t1 ## from 0-diagonal to unit-diagonal {low-level step}: tu <- t1 ; tu@diag <- "U" tu (cu <- as(tu, "CsparseMatrix")) str(cu)# only two entries in @i and @x stopifnot(cu@i == 1:0, all(2 * symmpart(cu) == Diagonal(4) + forceSymmetric(cu))) t1[1,2:3] <- -1:-2 diag(t1) <- 10*c(1:2,3:2) t1 # still triangular (it1 <- solve(t1)) t1. <- solve(it1) all(abs(t1 - t1.) < 10 * .Machine$double.eps) ## 2nd example U5 <- new("dtCMatrix", i= c(1L, 0:3), p=c(0L,0L,0:2, 5L), Dim = c(5L, 5L), x = rep(1, 5), diag = "U") U5 (iu <- solve(U5)) # contains one '0' validObject(iu2 <- solve(U5, Diagonal(5)))# failed in earlier versions I5 <- iu %*% U5 # should equal the identity matrix i5 <- iu2 %*% U5 m53 <- matrix(1:15, 5,3, dimnames=list(NULL,letters[1:3])) asDiag <- function(M) as(drop0(M), "diagonalMatrix") stopifnot( all.equal(Diagonal(5), asDiag(I5), tolerance=1e-14) , all.equal(Diagonal(5), asDiag(i5), tolerance=1e-14) , identical(list(NULL, dimnames(m53)[[2]]), dimnames(solve(U5, m53))) )showClass("TsparseMatrix") ## or just the subclasses' names names(getClass("TsparseMatrix")@subclasses) T3 <- spMatrix(3,4, i=c(1,3:1), j=c(2,4:2), x=1:4) T3 # only 3 non-zero entries, 5 = 1+4 ! m <- Matrix(0+1:28, nrow = 4) m[-3,c(2,4:5,7)] <- m[ 3, 1:4] <- m[1:3, 6] <- 0 (mT <- as(m, "TsparseMatrix")) str(mT) mT[1,] mT[4, drop = FALSE] stopifnot(identical(mT[lower.tri(mT)], m [lower.tri(m) ])) mT[lower.tri(mT,diag=TRUE)] <- 0 mT ## Triplet representation with repeated (i,j) entries ## *adds* the corresponding x's: T2 <- new("dgTMatrix", i = as.integer(c(1,1,0,3,3)), j = as.integer(c(2,2,4,0,0)), x=10*1:5, Dim=4:5) str(T2) # contains (i,j,x) slots exactly as above, but T2 ## has only three non-zero entries, as for repeated (i,j)'s, ## the corresponding x's are "implicitly" added stopifnot(nnzero(T2) == 3) mm <- Matrix(toeplitz(c(10, 0, 1, 0, 3)), sparse = TRUE) mm # automatically dsCMatrix str(mm) mT <- as(as(mm, "generalMatrix"), "TsparseMatrix") ## Either (symM <- as(mT, "symmetricMatrix")) # dsT (symC <- as(symM, "CsparseMatrix")) # dsC ## or sT <- Matrix(mT, sparse=TRUE, forceCheck=TRUE) # dsT sym2 <- as(symC, "TsparseMatrix") ## --> the same as 'symM', a "dsTMatrix" showClass("dtCMatrix") showClass("dtTMatrix") t1 <- new("dtTMatrix", x= c(3,7), i= 0:1, j=3:2, Dim= as.integer(c(4,4))) t1 ## from 0-diagonal to unit-diagonal {low-level step}: tu <- t1 ; tu@diag <- "U" tu (cu <- as(tu, "CsparseMatrix")) str(cu)# only two entries in @i and @x stopifnot(cu@i == 1:0, all(2 * symmpart(cu) == Diagonal(4) + forceSymmetric(cu))) t1[1,2:3] <- -1:-2 diag(t1) <- 10*c(1:2,3:2) t1 # still triangular (it1 <- solve(t1)) t1. <- solve(it1) all(abs(t1 - t1.) < 10 * .Machine$double.eps) ## 2nd example U5 <- new("dtCMatrix", i= c(1L, 0:3), p=c(0L,0L,0:2, 5L), Dim = c(5L, 5L), x = rep(1, 5), diag = "U") U5 (iu <- solve(U5)) # contains one '0' validObject(iu2 <- solve(U5, Diagonal(5)))# failed in earlier versions I5 <- iu %*% U5 # should equal the identity matrix i5 <- iu2 %*% U5 m53 <- matrix(1:15, 5,3, dimnames=list(NULL,letters[1:3])) asDiag <- function(M) as(drop0(M), "diagonalMatrix") stopifnot( all.equal(Diagonal(5), asDiag(I5), tolerance=1e-14) , all.equal(Diagonal(5), asDiag(i5), tolerance=1e-14) , identical(list(NULL, dimnames(m53)[[2]]), dimnames(solve(U5, m53))) )
unpackedMatrix is a virtual subclass of
denseMatrix representing conventional dense
format matrices, as defined by LAPACK:
https://netlib.org/lapack/lug/node121.html. To represent an
m-by-n matrix A, this format stores a vector of
length m*n, of which m*n or fewer elements are
actually used (fewer if there are formal constraints on the structure
of A). Within package Matrix, this format is called
“unpacked” to emphasize that it is complementary to the packed
format also defined by LAPACK.
Dim, Dimnames
inherited from virtual superclass
Matrix.
xa vector of length prod(Dim) storing entries
of A in column-major order. Authors of subclasses of
unpackedMatrix may declare that only a subset k of
the elements of x is used to determine A, defining
implicitly a function F such that A = F(x[k]); see
‘Subclasses’ for examples in package Matrix.
The nonvirtual subclasses of unpackedMatrix defined in package
Matrix are listed below with links to virtual superclasses
defining their data type and structure.
| Nonvirtual subclass | Data type | Structure |
ngeMatrix |
nMatrix |
generalMatrix
|
lgeMatrix |
lMatrix |
generalMatrix
|
igeMatrix |
iMatrix |
generalMatrix
|
dgeMatrix |
dMatrix |
generalMatrix
|
zgeMatrix |
zMatrix |
generalMatrix
|
nsyMatrix |
nMatrix |
symmetricMatrix
|
lsyMatrix |
lMatrix |
symmetricMatrix
|
isyMatrix |
iMatrix |
symmetricMatrix
|
dsyMatrix |
dMatrix |
symmetricMatrix
|
zsyMatrix |
zMatrix |
symmetricMatrix
|
dpoMatrix |
dMatrix |
posdefMatrix
|
zpoMatrix |
zMatrix |
posdefMatrix
|
ntrMatrix |
nMatrix |
triangularMatrix
|
ltrMatrix |
lMatrix |
triangularMatrix
|
itrMatrix |
iMatrix |
triangularMatrix
|
dtrMatrix |
dMatrix |
triangularMatrix
|
ztrMatrix |
zMatrix |
triangularMatrix
|
The subclasses of iMatrix and zMatrix were not defined
until Matrix version 1.8-0. The other subclasses predate
unpackedMatrix itself, which was not defined until Matrix
version 1.5-0; previously, those subclasses were direct extensions of
denseMatrix.
The mapping from the x slot of length m*n to the
m-by-n represented matrix A is given by:
A[i, j]
| i < j | i = j | i > j
|--------------------|----------------------|--------------------
.geMatrix | x[(j-1)*m+i] | x[(j-1)*m+i] | x[(j-1)*m+i]
.syMatrix, uplo="U" | x[(j-1)*m+i] | x[(j-1)*m+i] | x[(i-1)*m+j]
zsyMatrix, uplo="U", trans="C" | x[(j-1)*m+i] | Re(x[(j-1)*m+i])+0i | Conj(x[(i-1)*m+j])
.syMatrix, uplo="L" | x[(i-1)*m+j] | x[(j-1)*m+i] | x[(j-1)*m+i]
zsyMatrix, uplo="L", trans="C" | Conj(x[(i-1)*m+j]) | Re(x[(j-1)*m+i])+0i | x[(j-1)*m+i]
.trMatrix, uplo="U", diag="N" | x[(j-1)*m+i] | x[(j-1)*m+i] | 0
.trMatrix, uplo="U", diag="U" | x[(j-1)*m+i] | 1 | 0
.trMatrix, uplo="L", diag="N" | 0 | x[(j-1)*m+i] | x[(j-1)*m+j]
.trMatrix, uplo="L", diag="U" | 0 | 1 | x[(j-1)*m+j]
Classes .geMatrix represent general (that is, unstructured)
A. Objects have an x slot that stores all m*n
entries of A. These classes closely approximate traditional
matrices. For example, a traditional matrix z of type
integer and its analogue Z of formal class
igeMatrix are related by:
z <- array(Z@x, dim = Z@Dim, dimnames = Z@Dimnames)
Z <- new("igeMatrix", Dim = dim(z), Dimnames = dimnames(z), x = as.vector(z))
Classes .syMatrix represent Hermitian or symmetric A.
Objects have x and uplo slots. If uplo="U", then
x[row(A) <= col(A)] stores the n*(n+1)/2 upper
triangular entries of A and x[row(A) > col(A)] is
unreferenced. If uplo="L", then x[row(A) >= col(A)]
stores the n*(n+1)/2 lower triangular entries of A and
x[row(A) < col(A)] is unreferenced. Objects of class
zsyMatrix have an additional trans slot that
distinguishes Hermitian and symmetric A, which use
trans="C" and "T", respectively. If trans="C",
then the imaginary parts of x[row(A) == col(A)] are not
referenced. (The diagonal entries of Hermitian matrices are real by
definition.)
Classes dpoMatrix and zpoMatrix extend dsyMatrix
and zsyMatrix and represent positive semidefinite A.
Positive semidefiniteness of A induces a constraint on the
x slot. However, this constraint is not strictly enforced by
the validity methods, which test only that the diagonal entries of
A are nonnegative (a necessary, not sufficient condition).
For zpoMatrix, only trans="C" is valid. Class
corMatrix extends dpoMatrix and represents correlation
matrices; it has an additional sd slot, a numeric vector of
length n listing standard deviations, enabling recovery of a
covariance matrix.
Classes .trMatrix represent triangular A. Objects have
x, uplo, and diag slots. If uplo="U",
then A is upper triangular, x[row(A) < col(A)] stores
the n*(n-1)/2 strictly upper triangular entries, and
x[row(A) > col(A)] is unreferenced. If uplo="L", then
A is lower triangular, x[row(A) > col(A)] stores the
n*(n-1)/2 strictly lower triangular entries, and
x[row(A) < col(A)] is unreferenced. If diag="N", then
x[row(A) == col(A)] stores the n diagonal entries of
A. If diag="U", then A is unit triangular and
those elements of x are unreferenced.
“Complementary” class packedMatrix
representing packed dense format matrices. Generic function
pack, an alternative to explicit coercion to
packedMatrix.
showClass("unpackedMatrix") showMethods(classes = "unpackedMatrix") showClass("ngeMatrix") ## "lgeMatrix" is really more relevant showClass("lgeMatrix") str(new("lgeMatrix")) set.seed(1) (lM <- Matrix(matrix(rnorm(28), 4,7) > 0))# a simple random lgeMatrix set.seed(11) (lC <- Matrix(matrix(rnorm(28), 4,7) > 0))# a simple random lgCMatrix as(lM, "CsparseMatrix") (s0 <- new("nsyMatrix")) (M2 <- Matrix(c(TRUE, NA, FALSE, FALSE), 2, 2)) # logical dense (ltr) (sM <- M2 & t(M2)) # -> "lge" class(sM <- as(sM, "nMatrix")) # -> "nge" (sM <- as(sM, "symmetricMatrix")) # -> "nsy" str(sM <- as(sM, "packedMatrix")) # -> "nsp", i.e., packed symmetric (M2 <- Matrix(c(TRUE, NA, FALSE, FALSE), 2, 2)) # logical dense (ltr) str(M2) # can (sM <- M2 | t(M2)) # "lge" as(sM, "symmetricMatrix") str(sM <- as(sM, "packedMatrix")) # packed symmetric ## Only upper triangular part matters (when uplo == "U" as per default) (sy2 <- new("dsyMatrix", Dim = as.integer(c(2,2)), x = c(14, NA,32,77))) str(t(sy2)) # uplo = "L", and the lower tri. (i.e. NA is replaced). chol(sy2) #-> "Cholesky" matrix (sp2 <- pack(sy2)) # a "dspMatrix" ## Coercing to dpoMatrix gives invalid object: sy3 <- new("dsyMatrix", Dim = as.integer(c(2,2)), x = c(14, -1, 2, -7)) try(as(sy3, "dpoMatrix")) # -> error: not positive definite ## 4x4 example m <- matrix(0,4,4); m[upper.tri(m)] <- 1:6 (sym <- m+t(m)+diag(11:14, 4)) (S1 <- pack(sym)) (S2 <- t(S1)) stopifnot(all(S1 == S2)) # equal "seen as matrix", but differ internally : str(S1) S2@x showClass("ntrMatrix") str(new("ntpMatrix")) (nutr <- as(upper.tri(matrix(, 4, 4)), "ndenseMatrix")) str(nutp <- pack(nutr)) # packed matrix: only 10 = 4*(4+1)/2 entries !nutp # the logical negation (is *not* logical triangular !) ## but this one is: stopifnot(all.equal(nutp, pack(!!nutp))) showClass("ltrMatrix") str(new("ltpMatrix")) (lutr <- as(upper.tri(matrix(, 4, 4)), "ldenseMatrix")) str(lutp <- pack(lutr)) # packed matrix: only 10 = 4*(4+1)/2 entries !lutp # the logical negation (is *not* logical triangular !) ## but this one is: stopifnot(all.equal(lutp, pack(!!lutp))) (m <- rbind(2:3, 0:-1)) (M <- as(m, "generalMatrix")) (T <- as(M, "triangularMatrix")) # formally upper triangular (T2 <- as(t(M), "triangularMatrix")) stopifnot(T@uplo == "U", T2@uplo == "L", identical(T2, t(T))) m <- matrix(0,4,4); m[upper.tri(m)] <- 1:6 (t1 <- Matrix(m+diag(,4))) str(t1p <- pack(t1)) (t1pu <- diagN2U(t1p)) stopifnot(exprs = { inherits(t1 , "dtrMatrix"); validObject(t1) inherits(t1p, "dtpMatrix"); validObject(t1p) inherits(t1pu,"dtCMatrix"); validObject(t1pu) t1pu@x == 1:6 all(t1pu == t1p) identical((t1pu - t1)@x, numeric())# sparse all-0 })showClass("unpackedMatrix") showMethods(classes = "unpackedMatrix") showClass("ngeMatrix") ## "lgeMatrix" is really more relevant showClass("lgeMatrix") str(new("lgeMatrix")) set.seed(1) (lM <- Matrix(matrix(rnorm(28), 4,7) > 0))# a simple random lgeMatrix set.seed(11) (lC <- Matrix(matrix(rnorm(28), 4,7) > 0))# a simple random lgCMatrix as(lM, "CsparseMatrix") (s0 <- new("nsyMatrix")) (M2 <- Matrix(c(TRUE, NA, FALSE, FALSE), 2, 2)) # logical dense (ltr) (sM <- M2 & t(M2)) # -> "lge" class(sM <- as(sM, "nMatrix")) # -> "nge" (sM <- as(sM, "symmetricMatrix")) # -> "nsy" str(sM <- as(sM, "packedMatrix")) # -> "nsp", i.e., packed symmetric (M2 <- Matrix(c(TRUE, NA, FALSE, FALSE), 2, 2)) # logical dense (ltr) str(M2) # can (sM <- M2 | t(M2)) # "lge" as(sM, "symmetricMatrix") str(sM <- as(sM, "packedMatrix")) # packed symmetric ## Only upper triangular part matters (when uplo == "U" as per default) (sy2 <- new("dsyMatrix", Dim = as.integer(c(2,2)), x = c(14, NA,32,77))) str(t(sy2)) # uplo = "L", and the lower tri. (i.e. NA is replaced). chol(sy2) #-> "Cholesky" matrix (sp2 <- pack(sy2)) # a "dspMatrix" ## Coercing to dpoMatrix gives invalid object: sy3 <- new("dsyMatrix", Dim = as.integer(c(2,2)), x = c(14, -1, 2, -7)) try(as(sy3, "dpoMatrix")) # -> error: not positive definite ## 4x4 example m <- matrix(0,4,4); m[upper.tri(m)] <- 1:6 (sym <- m+t(m)+diag(11:14, 4)) (S1 <- pack(sym)) (S2 <- t(S1)) stopifnot(all(S1 == S2)) # equal "seen as matrix", but differ internally : str(S1) S2@x showClass("ntrMatrix") str(new("ntpMatrix")) (nutr <- as(upper.tri(matrix(, 4, 4)), "ndenseMatrix")) str(nutp <- pack(nutr)) # packed matrix: only 10 = 4*(4+1)/2 entries !nutp # the logical negation (is *not* logical triangular !) ## but this one is: stopifnot(all.equal(nutp, pack(!!nutp))) showClass("ltrMatrix") str(new("ltpMatrix")) (lutr <- as(upper.tri(matrix(, 4, 4)), "ldenseMatrix")) str(lutp <- pack(lutr)) # packed matrix: only 10 = 4*(4+1)/2 entries !lutp # the logical negation (is *not* logical triangular !) ## but this one is: stopifnot(all.equal(lutp, pack(!!lutp))) (m <- rbind(2:3, 0:-1)) (M <- as(m, "generalMatrix")) (T <- as(M, "triangularMatrix")) # formally upper triangular (T2 <- as(t(M), "triangularMatrix")) stopifnot(T@uplo == "U", T2@uplo == "L", identical(T2, t(T))) m <- matrix(0,4,4); m[upper.tri(m)] <- 1:6 (t1 <- Matrix(m+diag(,4))) str(t1p <- pack(t1)) (t1pu <- diagN2U(t1p)) stopifnot(exprs = { inherits(t1 , "dtrMatrix"); validObject(t1) inherits(t1p, "dtpMatrix"); validObject(t1p) inherits(t1pu,"dtCMatrix"); validObject(t1pu) t1pu@x == 1:6 all(t1pu == t1p) identical((t1pu - t1)@x, numeric())# sparse all-0 })
S4 methods defined in package Matrix for S4 generic function
update, generalizing stats::update.
The method for virtual class sparseCholesky
adjusts the numeric entries of a sparse Cholesky factorization to a
new sparse matrix. It changes factorizations of
to factorizations of
where the new matrix is constrained to have
nonzero pattern identical to that of the old matrix .
## S4 method for signature 'sparseCholesky' update(object, parent, mult = 0, ...)## S4 method for signature 'sparseCholesky' update(object, parent, mult = 0, ...)
object |
a |
parent |
a |
mult |
a numeric or complex vector of positive length. |
... |
optional arguments not yet used. |
A new sparseCholesky object representing the
Cholesky factorization of op(parent) plus mult[1] times
the identity matrix, where op is identity for
formally Hermitian parent and
tcrossprod(trans = "C") for all other parent.
Virtual class sparseCholesky.
Generic functions Cholesky and
updown.
set.seed(44L) X <- rsparsematrix(1000L, 200L, 0.01) A <- crossprod(X) u0 <- u0. <- Cholesky(A, LDL = FALSE) u1 <- update(u0, parent = 4 * A) u2 <- update(u0, parent = A , mult = 2) u3 <- update(u0, parent = t(X), mult = 2) u0.@x <- 2 * u0.@x stopifnot(all.equal(u1, u0., tolerance = 1e-14), all.equal(u3, u2 , tolerance = 1e-14))set.seed(44L) X <- rsparsematrix(1000L, 200L, 0.01) A <- crossprod(X) u0 <- u0. <- Cholesky(A, LDL = FALSE) u1 <- update(u0, parent = 4 * A) u2 <- update(u0, parent = A , mult = 2) u3 <- update(u0, parent = t(X), mult = 2) u0.@x <- 2 * u0.@x stopifnot(all.equal(u1, u0., tolerance = 1e-14), all.equal(u3, u2 , tolerance = 1e-14))
Computes a rank- update or downdate of a Cholesky factorization
which for some -column matrix is the factorization
Here, for an update and for a downdate.
updown(update, C, L) ## S4 method for signature 'character,ANY,ANY' updown(update, C, L) ## S4 method for signature 'logical,Matrix,sparseCholesky' updown(update, C, L) ## S4 method for signature 'logical,matrix,sparseCholesky' updown(update, C, L)updown(update, C, L) ## S4 method for signature 'character,ANY,ANY' updown(update, C, L) ## S4 method for signature 'logical,Matrix,sparseCholesky' updown(update, C, L) ## S4 method for signature 'logical,matrix,sparseCholesky' updown(update, C, L)
update |
a logical ( |
C |
an R object representing the |
L |
an R object representing the original Cholesky
factorization. Package Matrix provides methods for virtual
class |
An R object representing the updated or downdated Cholesky factorization.
Methods provided by package Matrix return a new
sparseCholesky object. The new factorization is
square root-free, even if the old one is not, hence it is required
that has nonzero leading principal
minors, not that it is positive definite.
Nicholas Nagle (University of Tennessee, Knoxville) provided the original implementation.
Davis, T. A., Hager, W. W. (2001). Multiple-rank modifications of a sparse Cholesky factorization. SIAM Journal on Matrix Analysis and Applications, 22(4), 997-1013. doi:10.1137/S0895479899357346
Virtual class sparseCholesky.
Generic function Cholesky.
The method for generic function update with
signature c(object="sparseCholesky"), which is not
equivalent to updown(update = TRUE, C = ., L = object).
X <- new("dgCMatrix", Dim = c(3L, 5L), p = c(0L, 1L, 2L, 4L, 4L, 6L), i = c(2L, 0L, 1L, 2L, 0L, 1L), x = as.double(1:6)) I5 <- new("ddiMatrix", Dim = c(5L, 5L), diag = "U") A <- crossprod(X) + I5 u0 <- Cholesky(A) u1 <- updown("+", I5, u0) u2 <- updown("-", I5, u1) stopifnot(all.equal(u0, u2))X <- new("dgCMatrix", Dim = c(3L, 5L), p = c(0L, 1L, 2L, 4L, 4L, 6L), i = c(2L, 0L, 1L, 2L, 0L, 1L), x = as.double(1:6)) I5 <- new("ddiMatrix", Dim = c(5L, 5L), diag = "U") A <- crossprod(X) + I5 u0 <- Cholesky(A) u1 <- updown("+", I5, u0) u2 <- updown("-", I5, u1) stopifnot(all.equal(u0, u2))
This matrix gives the contiguities of 3111 U.S. counties, using the queen criterion of at least one shared vertex or edge.
data(USCounties)data(USCounties)
A sparse, symmetric
matrix of class dsCMatrix, with 9101
nonzero entries.
GAL lattice file ‘usc_q.GAL’
(retrieved in 2008 from
‘http://sal.uiuc.edu/weights/zips/usc.zip’
with permission from Luc Anselin for use and distribution)
was read into R using function read.gal
from package spdep.
Neighbour lists were augmented with row-standardized
(and then symmetrized) spatial weights, using functions
nb2listw and similar.listw from packages
spdep and spatialreg.
The resulting listw object was coerced to class
dsTMatrix
using as_dsTMatrix_listw from spatialreg,
and subsequently to class dsCMatrix.
Ord, J. K. (1975). Estimation methods for models of spatial interaction. Journal of the American Statistical Association, 70(349), 120-126. doi:10.2307/2285387
data(USCounties, package = "Matrix") (n <- ncol(USCounties)) I <- .symDiagonal(n) set.seed(1) r <- 50L rho <- 1 / runif(r, 0, 0.5) system.time(MJ0 <- sapply(rho, function(mult) determinant(USCounties + mult * I, logarithm = TRUE)$modulus)) ## Can be done faster by updating the Cholesky factor: C1 <- Cholesky(USCounties, Imult = 2) system.time(MJ1 <- sapply(rho, function(mult) determinant(update(C1, USCounties, mult), sqrt = FALSE)$modulus)) stopifnot(all.equal(MJ0, MJ1)) C2 <- Cholesky(USCounties, super = TRUE, Imult = 2) system.time(MJ2 <- sapply(rho, function(mult) determinant(update(C2, USCounties, mult), sqrt = FALSE)$modulus)) stopifnot(all.equal(MJ0, MJ2))data(USCounties, package = "Matrix") (n <- ncol(USCounties)) I <- .symDiagonal(n) set.seed(1) r <- 50L rho <- 1 / runif(r, 0, 0.5) system.time(MJ0 <- sapply(rho, function(mult) determinant(USCounties + mult * I, logarithm = TRUE)$modulus)) ## Can be done faster by updating the Cholesky factor: C1 <- Cholesky(USCounties, Imult = 2) system.time(MJ1 <- sapply(rho, function(mult) determinant(update(C1, USCounties, mult), sqrt = FALSE)$modulus)) stopifnot(all.equal(MJ0, MJ1)) C2 <- Cholesky(USCounties, super = TRUE, Imult = 2) system.time(MJ2 <- sapply(rho, function(mult) determinant(update(C2, USCounties, mult), sqrt = FALSE)$modulus)) stopifnot(all.equal(MJ0, MJ2))
S4 methods defined in package Matrix for S4 generic function
which, generalizing base::which.
## S4 method for signature 'ndenseMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'ndiMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'nsparseMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'nsparseVector' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'indMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'ldenseMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'ldiMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'lsparseMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'lsparseVector' which(x, arr.ind = FALSE, useNames = TRUE)## S4 method for signature 'ndenseMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'ndiMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'nsparseMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'nsparseVector' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'indMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'ldenseMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'ldiMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'lsparseMatrix' which(x, arr.ind = FALSE, useNames = TRUE) ## S4 method for signature 'lsparseVector' which(x, arr.ind = FALSE, useNames = TRUE)
x |
a |
arr.ind |
a logical indicating if array indices are computed and
returned when |
useNames |
a logical, passed to |
An integer or double vector or a two-column integer matrix, following
base::which.
## Column index matrix: matrix whose columns are standard unit vectors n <- 6L r <- 4L (J <- new("indMatrix", Dim = c(n, r), Dimnames = list(u=NULL, v=NULL), margin = 2L, perm = sample(n, r, replace=TRUE))) (w0 <- which(J)) (w1 <- which(J, arr.ind = TRUE)) stopifnot(identical(w0, 0L:(r - 1L) * n + J@perm), identical(w1, cbind(u=J@perm, v=1L:r)))## Column index matrix: matrix whose columns are standard unit vectors n <- 6L r <- 4L (J <- new("indMatrix", Dim = c(n, r), Dimnames = list(u=NULL, v=NULL), margin = 2L, perm = sample(n, r, replace=TRUE))) (w0 <- which(J)) (w1 <- which(J, arr.ind = TRUE)) stopifnot(identical(w0, 0L:(r - 1L) * n + J@perm), identical(w1, cbind(u=J@perm, v=1L:r)))
This matrix gives the contiguities of 15260 one-degree grid cells of world land areas, using a criterion based on the great-circle distance between centers.
data(wrld_1deg)data(wrld_1deg)
A sparse, symmetric
matrix of class dsCMatrix, with 55973
nonzero entries.
Shoreline data were read into R from the GSHHS database
using function Rgshhs from package maptools.
Antarctica was excluded. An approximately one-degree grid
was generated using function Sobj_SpatialGrid, also
from maptools. Grid cells with centers on land
were identified using the over method for classes
SpatialPolygons and SpatialGrid, defined in
package sp. Neighbours of these were identified
by passing the resulting SpatialPixels object to
function dnearneigh from package spdep,
using as a cut-off a great-circle distance of sqrt(2)
kilometers between centers.
Neighbour lists were augmented with row-standardized
(and then symmetrized) spatial weights, using functions
nb2listw and similar.listw from packages
spdep and spatialreg.
The resulting listw object was coerced to class
dsTMatrix
using as_dsTMatrix_listw from spatialreg,
and subsequently to class dsCMatrix.
Ord, J. K. (1975). Estimation methods for models of spatial interaction. Journal of the American Statistical Association, 70(349), 120-126. doi:10.2307/2285387
data(wrld_1deg, package = "Matrix") (n <- ncol(wrld_1deg)) I <- .symDiagonal(n) doExtras <- interactive() || nzchar(Sys.getenv("R_MATRIX_CHECK_EXTRA")) set.seed(1) r <- if(doExtras) 20L else 3L rho <- 1 / runif(r, 0, 0.5) system.time(MJ0 <- sapply(rho, function(mult) determinant(wrld_1deg + mult * I, logarithm = TRUE)$modulus)) ## Can be done faster by updating the Cholesky factor: C1 <- Cholesky(wrld_1deg, Imult = 2) system.time(MJ1 <- sapply(rho, function(mult) determinant(update(C1, wrld_1deg, mult), sqrt = FALSE)$modulus)) stopifnot(all.equal(MJ0, MJ1)) C2 <- Cholesky(wrld_1deg, super = TRUE, Imult = 2) system.time(MJ2 <- sapply(rho, function(mult) determinant(update(C2, wrld_1deg, mult), sqrt = FALSE)$modulus)) stopifnot(all.equal(MJ0, MJ2))data(wrld_1deg, package = "Matrix") (n <- ncol(wrld_1deg)) I <- .symDiagonal(n) doExtras <- interactive() || nzchar(Sys.getenv("R_MATRIX_CHECK_EXTRA")) set.seed(1) r <- if(doExtras) 20L else 3L rho <- 1 / runif(r, 0, 0.5) system.time(MJ0 <- sapply(rho, function(mult) determinant(wrld_1deg + mult * I, logarithm = TRUE)$modulus)) ## Can be done faster by updating the Cholesky factor: C1 <- Cholesky(wrld_1deg, Imult = 2) system.time(MJ1 <- sapply(rho, function(mult) determinant(update(C1, wrld_1deg, mult), sqrt = FALSE)$modulus)) stopifnot(all.equal(MJ0, MJ1)) C2 <- Cholesky(wrld_1deg, super = TRUE, Imult = 2) system.time(MJ2 <- sapply(rho, function(mult) determinant(update(C2, wrld_1deg, mult), sqrt = FALSE)$modulus)) stopifnot(all.equal(MJ0, MJ2))
S4 methods defined in package Matrix for S4 generic function
zapsmall, generalizing base::zapsmall.
The S4 generic function definition is obtained from package
methods through the implicitGeneric mechanism.
## S4 method for signature 'Matrix' zapsmall(x, digits = getOption("digits"), mFUN = function(x, ina) max(abs(x[!ina])), min.d = 0L, ...) ## S4 method for signature 'sparseVector' zapsmall(x, digits = getOption("digits"), mFUN = function(x, ina) max(abs(x[!ina])), min.d = 0L, ...)## S4 method for signature 'Matrix' zapsmall(x, digits = getOption("digits"), mFUN = function(x, ina) max(abs(x[!ina])), min.d = 0L, ...) ## S4 method for signature 'sparseVector' zapsmall(x, digits = getOption("digits"), mFUN = function(x, ina) max(abs(x[!ina])), min.d = 0L, ...)
x |
a |
digits, mFUN, min.d
|
additional arguments passed to
|
... |
optional arguments not yet used. |
Methods preserve the nonzero pattern of sparse format x: zeros
introduced by rounding are nonstructural.
An object representing the result of rounding x. The class is
a superclass of the class of x unless x has pattern,
logical, or integer data.
drop0 for deleting small (on an absolute scale) entries.
x <- new("dgCMatrix", Dim = c(3L, 2L), p = c(0L, 3L, 4L), i = c(0L, 1L, 2L, 1L), x = c(0, 1, -51, 1e+6)) # maximum absolute value is 10^6 x zapsmall(x, digits = 4L, min.d = -Inf) # rounds to nearest 10^(6-4) zapsmall(x, digits = 3L, min.d = -Inf) # rounds to nearest 10^(6-3)x <- new("dgCMatrix", Dim = c(3L, 2L), p = c(0L, 3L, 4L), i = c(0L, 1L, 2L, 1L), x = c(0, 1, -51, 1e+6)) # maximum absolute value is 10^6 x zapsmall(x, digits = 4L, min.d = -Inf) # rounds to nearest 10^(6-4) zapsmall(x, digits = 3L, min.d = -Inf) # rounds to nearest 10^(6-3)
zMatrix is a virtual subclass of Matrix
representing complex matrices. zdenseMatrix and
zsparseMatrix are virtual subclasses of zMatrix
representing its intersections with denseMatrix
and sparseMatrix.
Dim, Dimnames
inherited from virtual superclass
Matrix.
xa complex vector storing matrix entries. Details such as which entries are stored vary by storage format.
The nonvirtual subclasses of zMatrix are listed below with
links to virtual superclasses defining their structure and storage
format.
| Nonvirtual subclass | Structure | Storage format |
zgeMatrix |
generalMatrix |
unpackedMatrix
|
zsyMatrix |
symmetricMatrix |
unpackedMatrix
|
zpoMatrix |
posdefMatrix |
unpackedMatrix
|
ztrMatrix |
triangularMatrix |
unpackedMatrix
|
zspMatrix |
symmetricMatrix |
packedMatrix
|
zppMatrix |
posdefMatrix |
packedMatrix
|
ztpMatrix |
triangularMatrix |
packedMatrix
|
zgCMatrix |
generalMatrix |
CsparseMatrix
|
zsCMatrix |
symmetricMatrix |
CsparseMatrix
|
zpCMatrix |
posdefMatrix |
CsparseMatrix
|
ztCMatrix |
triangularMatrix |
CsparseMatrix
|
zgRMatrix |
generalMatrix |
RsparseMatrix
|
zsRMatrix |
symmetricMatrix |
RsparseMatrix
|
zpRMatrix |
posdefMatrix |
RsparseMatrix
|
ztRMatrix |
triangularMatrix |
RsparseMatrix
|
zgTMatrix |
generalMatrix |
TsparseMatrix
|
zsTMatrix |
symmetricMatrix |
TsparseMatrix
|
zpTMatrix |
posdefMatrix |
TsparseMatrix
|
ztTMatrix |
triangularMatrix |
TsparseMatrix
|
zdiMatrix |
diagonalMatrix |
unnamed
|
Subclasses of zMatrix were not defined until Matrix
version 1.8-0.
“Sister” classes nMatrix,
lMatrix, iMatrix, and
dMatrix representing boolean, logical, integer,
and double precision matrices.
## TODO## TODO