40 lines
1.2 KiB
R
40 lines
1.2 KiB
R
#' Squared Frobenius norm of difference of Kronecker product matrices
|
|
#'
|
|
#' \|(A1 %x% ... %x% Ar - B1 %x% ... %x% Br\|_F
|
|
#'
|
|
#' This is equivalent to the expression
|
|
#' \code{norm(Reduce(kronecker, A) - Reduce(kronecker, B), "F")} but faster.
|
|
#'
|
|
#' @examples
|
|
#' A1 <- matrix(rnorm(5^2), 5)
|
|
#' A2 <- matrix(rnorm(7^2), 7)
|
|
#' B1 <- matrix(rnorm(5^2), 5)
|
|
#' B2 <- matrix(rnorm(7^2), 7)
|
|
#' stopifnot(all.equal(
|
|
#' dist.kron.norm(list(A1, A2), list(B1, B2)),
|
|
#' norm(kronecker(A1, A2) - kronecker(B1, B2), "F")
|
|
#' ))
|
|
#'
|
|
#' p <- c(3, 7, 5, 2)
|
|
#' A <- Map(function(pj) matrix(rnorm(pj^2), pj), p)
|
|
#' B <- Map(function(pj) matrix(rnorm(pj^2), pj), p)
|
|
#' stopifnot(all.equal(
|
|
#' dist.kron.norm(A, B),
|
|
#' norm(Reduce(kronecker, A) - Reduce(kronecker, B), "F")
|
|
#' ))
|
|
#'
|
|
#' @export
|
|
dist.kron.norm <- function(A, B, eps = .Machine$double.eps) {
|
|
if (is.list(A) && is.list(B)) {
|
|
norm2 <- prod(unlist(Map(function(x) sum(x^2), A))) -
|
|
2 * prod(unlist(Map(function(a, b) sum(a * b), A, B))) +
|
|
prod(unlist(Map(function(x) sum(x^2), B)))
|
|
} else if (is.matrix(A) && is.matrix(B)) {
|
|
norm2 <- sum((A - B)^2)
|
|
} else {
|
|
stop("Unexpected input")
|
|
}
|
|
|
|
if (abs(norm2) < .Machine$double.eps) 0 else sqrt(norm2)
|
|
}
|