#' 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, As) - Reduce(kronecker, Bs), "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) #' As <- Map(function(pj) matrix(rnorm(pj^2), pj), p) #' Bs <- Map(function(pj) matrix(rnorm(pj^2), pj), p) #' stopifnot(all.equal( #' dist.kron.norm(As, Bs), #' norm(Reduce(kronecker, As) - Reduce(kronecker, Bs), "F") #' )) #' #' @export dist.kron.norm <- function(As, Bs, eps = .Machine$double.eps) { if (is.list(As) && is.list(Bs)) { norm2 <- prod(unlist(Map(function(x) sum(x^2), As))) - 2 * prod(unlist(Map(function(a, b) sum(a * b), As, Bs))) + prod(unlist(Map(function(x) sum(x^2), Bs))) } else if (is.matrix(As) && is.matrix(Bs)) { norm2 <- sum((As - Bs)^2) } else { stop("Unexpected input") } if (abs(norm2) < .Machine$double.eps) 0 else sqrt(norm2) }