这个矩阵的使用方式实际上更为重要。在许多情况下,后续计算并不需要显式地构建矩阵。这个问答可能与您无关:
如何构建和存储大型下三角矩阵以进行矩阵向量乘法?,但它很适合说明我的观点。
引用:
给定两个向量x和s,我需要计算H % *% x + s = y。
这个矩阵只用于矩阵向量乘法吗?我们肯定可以跳过形成这个矩阵,因为乘法只是rbind(B,A,C)和x之间的滚动矩阵向量乘法。
MatVecMul <- function (A, B, C, nA, x, s) {
if (diff(dim(A))) stop("A is not a square matrix")
if (diff(dim(B))) stop("B is not a square matrix")
if (diff(dim(C))) stop("C is not a square matrix")
if (dim(A)[1] != dim(B)[1]) stop("A and B does not have the same dimension")
if (dim(A)[1] != dim(C)[1]) stop("A and C does not have the same dimension")
if (length(x) != nA * M) stop("dimension dismatch between matrix and vector")
if (length(x) %% length(s)) stop("length of 'x' does not divide length of 's'")
y <- numeric(length(x))
M <- dim(A)[1]
ind_x <- 1:M
y[1:(2 * M)] <- rbind(A, C) %*% x[ind_x]
ind_x <- ind_x + M
BAC <- rbind(B, A, C)
ind_y <- 1:(3 * M)
i <- 0
while (i < (nA - 2)) {
y[ind_y] <- y[ind_y] + BAC %*% x[ind_x]
ind_x <- ind_x + M
ind_y <- ind_y + M
i <- i + 1
}
ind_y <- ind_y[1:(2 * M)]
y[ind_y] <- y[ind_y] + rbind(B, A) %*% x[ind_x]
y + s
}
这是一个可重现的例子。
set.seed(0)
M <- 5
A <- matrix(runif(M * M), M)
B <- matrix(runif(M * M), M)
C <- matrix(runif(M * M), M)
nA <- 5
x <- runif(25)
s <- runif(25)
y <- MatVecMul(A, B, C, nA, x, s)
为了验证上述的
y
计算正确,我们需要明确构造
H
。有很多构造方法。
方法1:使用块对角线(稀疏)矩阵。
N <- nA * M
library(Matrix)
H1 <- bdiag(rep.int(list(A), nA))
H2 <- bdiag(rep.int(list(B), nA - 1))
H3 <- bdiag(rep.int(list(C), nA - 1))
H <- H1 +
rbind(cbind(Matrix(0, nrow(H2), M), H2), Matrix(0, M, N)) +
cbind(rbind(Matrix(0, M, ncol(H3)), H3), Matrix(0, N, M))
range((H %*% x)@x + s - y)
我们看到
MatVecMul
是正确的。
方法2:直接填充
该方法基于以下观察结果:
B
-------------
A B
C A B
C A B
C A B
C A
-------------
C
很容易先构建矩形矩阵,然后从中间子集出正方形矩阵。
BAC <- rbind(B, A, C)
nA <- 5
N <- nA * M
NR <- N + 2 * M
BAC_ind1D <- c(outer(1:nrow(BAC), seq(from = 0, by = NR, length = M), "+"))
fill_ind1D <- outer(BAC_ind1D, seq(from = 0, by = M * (NR + 1), length = nA), "+")
fill_ind2D <- arrayInd(fill_ind1D, c(NR, N))
library(Matrix)
Hsparse <- sparseMatrix(i = fill_ind2D[, 1], j = fill_ind2D[, 2], x = BAC)
Hsparse <- Hsparse[(M+1):(N+M), ]
Hdense <- matrix(0, NR, N)
Hdense[fill_ind2D] <- BAC
Hdense <- Hdense[(M+1):(N+M), ]
range((Hsparse %*% x)@x + s - y)
range(base::c(Hdense %*% x) + s - y)
再次看到,我们发现
MatVecMul
是正确的。
使用Rcpp实现MatVecMul
将R函数MatVecMul转换为Rcpp函数非常容易。我会把这个任务交给你,因为你已经使用过C++了。