#' 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 }