1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
### TODO: We really want the separate parts (P,L,D) of A = P' L D L' P
### --- --> ~/R/MM/Pkg-ex/Matrix/chol-ex.R ---------------
## but we currently only get A = P' L L' P --- now documented in ../man/Cholesky.Rd
setAs("CHMfactor", "sparseMatrix", function(from) .Call(CHMfactor_to_sparse, from))
setAs("CHMfactor", "triangularMatrix", function(from) .Call(CHMfactor_to_sparse, from))
setAs("CHMfactor", "Matrix", function(from) .Call(CHMfactor_to_sparse, from))
setAs("CHMfactor", "pMatrix", function(from) as(from@perm + 1L, "pMatrix"))
setMethod("expand", signature(x = "CHMfactor"),
function(x, ...)
list(P = as(x, "pMatrix"), L = as(x, "sparseMatrix")))
##' Determine if a CHMfactor object is LDL or LL
##' @param x - a CHMfactor object
##' @return TRUE if x is LDL, otherwise FALSE
isLDL <- function(x)
{
stopifnot(is(x, "CHMfactor"))
as.logical(! x@type[2])# "!" = not as type[2] := (cholmod_factor)->is_ll
}
.isLDL <- function(x) as.logical(! x@type[2])# "!" = not as type[2] := (cholmod_factor)->is_ll
setMethod("image", "CHMfactor",
function(x, ...) image(as(as(x, "sparseMatrix"), "dgTMatrix"), ...))
.CHM_solve <-
function(a, b,
system = c("A", "LDLt", "LD", "DLt", "L", "Lt", "D", "P", "Pt"),
...)
{
chk.s(..., which.call=-2)
sysDef <- eval(formals()$system)
.Call(CHMfactor_solve,
##-> cholmod_solve() in ../src/CHOLMOD/Cholesky/cholmod_solve.c
a, b,
## integer in 1 ("A"), 2 ("LDLt"), ..., 9 ("Pt") :
match(match.arg(system, sysDef), sysDef, nomatch = 0L))
}
setMethod("solve", signature(a = "CHMfactor", b = "ddenseMatrix"),
.CHM_solve, valueClass = "dgeMatrix")
setMethod("solve", signature(a = "CHMfactor", b = "matrix"),
.CHM_solve, valueClass = "dgeMatrix")
setMethod("solve", signature(a = "CHMfactor", b = "numeric"),
function(a, b, ...)
.CHM_solve(a, matrix(if(is.double(b)) b else as.double(b),
length(b), 1L), ...),
valueClass = "dgeMatrix")
setMethod("solve", signature(a = "CHMfactor", b = "dsparseMatrix"),
function(a, b,
system = c("A", "LDLt", "LD", "DLt", "L", "Lt", "D", "P", "Pt"),
...) {
chk.s(..., which.call=-2)
sysDef <- eval(formals()$system)
.Call(CHMfactor_spsolve, #--> cholmod_spsolve() in ../src/CHOLMOD/Cholesky/cholmod_spsolve.c
a, as(as(b, "CsparseMatrix"), "dgCMatrix"),
match(match.arg(system, sysDef), sysDef, nomatch = 0L))
}, valueClass = "CsparseMatrix")# < virtual value ?
setMethod("solve", signature(a = "CHMfactor", b = "diagonalMatrix"),
function(a, b, ...) solve(a, as(b, "dsparseMatrix"), ...))
setMethod("solve", signature(a = "CHMfactor", b = "missing"),
## <--> b = Diagonal(.)
function(a, b,
system = c("A", "LDLt", "LD","DLt", "L","Lt", "D", "P","Pt"),
...) {
chk.s(..., which.call=-2)
sysDef <- eval(formals()$system)
system <- match.arg(system, sysDef)
i.sys <- match(system, sysDef, nomatch = 0L)
as(.Call(CHMfactor_spsolve, a,
.sparseDiagonal(a@Dim[1], shape="g"), i.sys),
switch(system,
A=, LDLt = "symmetricMatrix",# was "dsCMatrix"
LD=, DLt=, L=, Lt =,
D = "dtCMatrix", # < diagonal: still as "Csparse.."
P=, Pt = "pMatrix"))
})
## Catch-all the rest : make sure 'system' is not lost
setMethod("solve", signature(a = "CHMfactor", b = "ANY"),
function(a, b, system = c("A", "LDLt", "LD","DLt", "L","Lt", "D", "P","Pt"),
...)
solve(a, as(b, "dMatrix"), system, ...))
setMethod("chol2inv", signature(x = "CHMfactor"),
function (x, ...) {
chk.s(..., which.call=-2)
solve(x, system = "A")
})
setMethod("determinant", signature(x = "CHMfactor", logarithm = "missing"),
function(x, logarithm, ...) determinant(x, TRUE))
setMethod("determinant", signature(x = "CHMfactor", logarithm = "logical"),
function(x, logarithm, ...)
{
ldet <- .Call(CHMfactor_ldetL2, x) / 2
mkDet(logarithm=logarithm, ldet=ldet, sig = 1L)
})
setMethod("update", signature(object = "CHMfactor"),
function(object, parent, mult = 0, ...)
{
stopifnot(extends(clp <- class(parent), "sparseMatrix"))
d <- dim(parent)
if(!extends(clp, "dsparseMatrix"))
clp <- class(parent <- as(parent, "dsparseMatrix"))
if(!extends(clp, "CsparseMatrix"))
clp <- class(parent <- as(parent, "CsparseMatrix"))
if(d[1] == d[2] && !extends(clp, "dsCMatrix") &&
!is.null(v <- getOption("Matrix.verbose")) && v >= 1)
message(gettextf("Quadratic matrix '%s' (=: A) is not formally\n symmetric. Will be treated as A A' ",
"parent"), domain=NA)
chk.s(..., which.call=-2)
.Call(CHMfactor_update, object, parent, mult)
})
##' fast version, somewhat hidden; here parent *must* be 'd[sg]CMatrix'
.updateCHMfactor <- function(object, parent, mult)
.Call(CHMfactor_update, object, parent, mult)
setMethod("updown", signature(update="ANY", C="ANY", L="ANY"),
## fallback method -- give a "good" error message:
function(update,C,L)
stop("'update' must be logical or '+' or '-'; 'C' a matrix, and 'L' a \"CHMfactor\""))
setMethod("updown", signature(update="logical", C="mMatrix", L="CHMfactor"),
function(update,C,L){
bnew <- as(L,'pMatrix') %*% C
.Call(CHMfactor_updown,update, as(bnew,'sparseMatrix'), L)
})
setMethod("updown", signature(update="character", C="mMatrix", L="CHMfactor"),
function(update,C,L){
if(! update %in% c("+","-"))
stop("update must be TRUE/FALSE or '+' or '-'")
update <- update=="+"
bnew <- as(L,'pMatrix') %*% C
.Call(CHMfactor_updown,update, as(bnew,'sparseMatrix'), L)
})
## Currently hidden:
ldetL2up <- function(x, parent, Imult)
{
## Purpose: compute log Det |A + m*I| for many values of m
## ----------------------------------------------------------------------
## Arguments: x: CHMfactor to be updated
## parent : CsparseMatrix M; for symmetric M, A = M, otherwise A = MM'
## Imult : a numeric *vector* of 'm's (= I multipliers)
## ----------------------------------------------------------------------
## Author: Doug Bates, Date: 19 Mar 2008
stopifnot(is(x, "CHMfactor"),
is(parent, "CsparseMatrix"),
nrow(x) == nrow(parent))
.Call(CHMfactor_ldetL2up, x, parent, as.double(Imult))
}
##' Update a sparse Cholesky factorization in place
##' @param L A sparse Cholesky factor that inherits from CHMfactor
##' @param parent a sparse matrix for updating the factor. Either a
##' dsCMatrix, in which case L is updated to the Cholesky
##' factorization of parent, or a dgCMatrix, in which case L is
##' updated to the Cholesky factorization of tcrossprod(parent)
##' @param Imult an optional positive scalar to be added to the
##' diagonal before factorization,
##' @return NULL. This function always returns NULL. It is called
##' for its side-effect of updating L in place.
##' @note This function violates the functional language semantics of
##' R in that it updates its argument L in place (i.e. without copying).
##' This is intentional but it means the function should be used
##' with caution. If the preceding sentences do not make sense to
##' you, you should not use this function,.
destructive_Chol_update <- function(L, parent, Imult = 1)
{
stopifnot(is(L, "CHMfactor"),
is(parent, "sparseMatrix"))
.Call(destructive_CHM_update, L, parent, Imult)
}
|