82 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			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
 | 
						|
}
 |