tensor_predictors/tensorPredictors/R/sym.R

82 lines
2.2 KiB
R

#' Generale a matrix of all permutations of `n` elements
permutations <- function(n) {
if (n <= 0) {
matrix(nrow = 0, ncol = 0)
} else if (n == 1) {
matrix(1)
} else {
sub.perm <- permutations(n - 1)
p <- nrow(sub.perm)
A <- matrix(NA, n * p, n)
for (i in 1:n) {
A[(i - 1) * p + 1:p, ] <- cbind(i, sub.perm + (sub.perm >= i))
}
A
}
}
#' General symmetrization opperation for tensors (arrays) of equal dimensions
#'
#' @param A array of dimensions c(p, ..., p)
#'
#' @returns array of same dimensions as `A`
#'
#' @export
tsym <- function(A) {
stopifnot(all(dim(A) == nrow(A)))
if (is.matrix(A)) {
return(0.5 * (A + t(A)))
}
axis.perm <- permutations(length(dim(A)))
S <- array(0, dim(A))
for (i in seq_len(nrow(axis.perm))) {
S <- S + aperm(A, axis.perm[i, ])
}
S / nrow(axis.perm)
}
#' Genralized (pseudo) symmetrication for generel multi-dimensional arrays
sym <- function(A, FUN = `+`, scale = factorial(length(dim(A)))) {
FUN <- match.fun(FUN)
if (is.matrix(A) && (nrow(A) == ncol(A))) {
A <- FUN(A, t(A))
return(if (is.numeric(scale)) A / scale else A)
}
A.copy <- A
perm <- seq_along(dim(A))
while (length(pivot <- which(diff(perm) > 0))) {
pivot <- max(pivot)
successor <- max(which(perm[seq_along(perm) > pivot] > perm[pivot])) + pivot
perm[c(pivot, successor)] <- perm[c(successor, pivot)]
suffix <- seq(pivot + 1, length(perm))
perm <- c(perm[-suffix], perm[rev(suffix)])
modes <- which(perm != seq_along(perm))
sub.dimA <- dim(A)
sub.dimA[modes] <- min(dim(A)[modes])
sub.indices <- Map(seq_len, sub.dimA)
sub.selection <- do.call(`[`, c(list(A.copy), sub.indices, drop = FALSE))
sub.assign <- do.call(call, c(list("[<-", quote(quote(A))), sub.indices,
quote(quote(FUN(
do.call(`[`, c(list(A), sub.indices)),
aperm(do.call(`[`, c(list(A.copy), sub.indices, drop = FALSE)), perm)
)))
))
A <- eval(sub.assign)
}
if (is.numeric(scale)) A / scale else A
}