當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


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。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。