当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


R Cholesky-methods Cholesky 分解方法


R语言 Cholesky-methods 位于 Matrix 包(package)。

说明

计算 实对称矩阵 的旋转 Cholesky 分解,其具有一般形式

或(等效地)

其中 是置换矩阵, 是单位下三角矩阵, 是对角矩阵, 。第二个等式仅适用于正半定 ,其中 的对角线条目是非负的,并且 是明确定义的。

denseMatrix 的方法基于 LAPACK 例程 dpstrfdpotrfdpptrf 构建。后两者不排列行或列,因此 是单位矩阵。

sparseMatrix 的方法基于 CHOLMOD 例程 cholmod_analyzecholmod_factorize_p 构建。

用法

Cholesky(A, ...)
## S4 method for signature 'dsyMatrix'
Cholesky(A, perm = TRUE, tol = -1, ...)
## S4 method for signature 'dspMatrix'
Cholesky(A, ...)
## S4 method for signature 'dsCMatrix'
Cholesky(A, perm = TRUE, LDL = !super, super = FALSE,
    Imult = 0, ...)
## S4 method for signature 'ddiMatrix'
Cholesky(A, ...)
## S4 method for signature 'generalMatrix'
Cholesky(A, uplo = "U", ...)
## S4 method for signature 'triangularMatrix'
Cholesky(A, uplo = "U", ...)
## S4 method for signature 'matrix'
Cholesky(A, uplo = "U", ...)

参数

A

要因式分解的 finite 、对称矩阵或 Matrix 。如果A是正方形但不对称,则将其视为对称;请参阅uplo。密集 A 的方法在 perm = FALSE 时需要正定性,在 perm = TRUE 时需要正半定性。稀疏 A 的方法在 LDL = TRUE 时需要正定性,在 LDL = FALSE 时需要非零前导主次要(旋转后)。稀疏对角线 A 的方法是一个例外,无条件要求正半定性。

perm

指示 的行和列是否应旋转的逻辑。稀疏 A 的方法采用近似最小度 (AMD) 算法来减少 fill-in,即不考虑数值稳定性。稀疏性可能会引入非正的主次数,导致因式分解失败,在这种情况下可能需要设置 perm = FALSE

tol

finite 数字容差,仅在 perm = TRUE 时使用。如果主元小于或等于 tol ,则因式分解算法停止。负数 tol 相当于 nrow(A) * .Machine$double.eps * max(diag(A))

LDL

一个逻辑,指示单纯因式分解是否应计算为 ,以便结果存储 的下三角条目。另一种方法是 ,这样结果存储 的下三角条目。如果 super = TRUE(或者选择 super = NA 和超节点算法),则忽略此参数,因为超节点代码尚不支持 LDL = TRUE 变体。

super

指示因式分解是否应使用超节点算法的逻辑。另一种选择是单纯算法。设置super = NA 将选择留给CHOLMOD-internal 启发式。

Imult

finite 号码。因式分解的矩阵为 A + Imult * diag(nrow(A)) ,即 A 加上 Imult 乘以单位矩阵。此参数对于对称、不定的 A 很有用,因为 Imult > max(rowSums(abs(A)) - diag(abs(A))) 确保 A + Imult * diag(nrow(A)) 对角占优。 (对称、对角占优矩阵是正定的。)

uplo

一个字符串,"U""L" ,指示应使用 A 的哪个三角形来计算因式分解。默认值为 "U" ,即使对于下三角 A ,也与 base 中的 chol 一致。

...

传入或传出方法的更多参数。

细节

请注意,调用 Cholesky 的结果继承自 CholeskyFactorization 但不是 Matrix 。仅需要矩阵的用户应考虑使用 chol ,其方法是 Cholesky 的简单包装器,仅返回上三角 Cholesky 因子 ,通常作为 triangularMatrix 。然而,更原则性的方法是根据需要从 CholeskyFactorization 对象构造因子,例如,如果 x 是对象,则使用 expand1(x, "L")

Cholesky(A, perm = TRUE) 对于密集 A 的行为有些例外,因为它期望不检查 A 是否为正半定。通过构造,如果 是半正定的并且精确算法遇到零主元,则未因式分解的尾随子矩阵是零矩阵,并且没有什么可做的。因此,当有限精度算法遇到小于 tol 的主元时,它会发出警告而不是错误信号,并将尾随子矩阵归零,以保证 是半正定的,即使 不是。因此,在出现警告时测试 的正半定性的一种方法是分析错误

有关详细信息,请参阅示例和 LAPACK 工作笔记 (“LAWN”) 161。

表示分解的对象,继承自虚拟类 CholeskyFactorization 。对于传统矩阵 A ,具体类是 Cholesky 。对于继承自 unpackedMatrixpackedMatrixsparseMatrixA ,具体类分别是 CholeskypCholeskydCHMsimpldCHMsuper

例子


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), "symmetricMatrix"))
    all.equal(A4, as(Reduce(`%*%`, E.ch.A4), "symmetricMatrix"))
})

## 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
.SuiteSparse_version()

参考

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

也可以看看

CholeskypCholeskydCHMsimpldCHMsuper 及其方法。

dpoMatrixdppMatrixdsCMatrix

通用函数 chol ,用于获取上三角 Cholesky 因子 作为矩阵或 Matrix

通用函数 expand1expand2 ,用于根据结果构造矩阵因子。

通用函数 BunchKaufmanSchurluqr 用于计算其他因式分解。

相关用法


注:本文由纯净天空筛选整理自R-devel大神的英文原创作品 Methods for Cholesky Factorization。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。