Here are some ideas for symbolic animation of matrices in R:
First we need to define the scalar product of the row and column. This can be done with:
wrap <- function(x) paste0("(",x,")") rowcol <- function(row,col) paste(wrap(row),wrap(col),sep="*",collapse="+")
Example:
> rowcol(c("A","B","C"),c("D","E","F")) [1] "(A)*(D)+(B)*(E)+(C)*(F)"
I had to βwrapβ each element in parentheses, since privileges greater than 2 can have more replicated expressions than one variable or a number (zero). Also note that zero will be displayed normally, i.e. He does not know (yet) that they can be simplified:
> rowcol(c("A","B"),c("0","X+Y")) [1] "(A)*(0)+(B)*(X+Y)"
Since these are valid expressions in R, this fact can be used to write a simplification function to eliminate zeros and redundant brackets. I will get there.
Now matrix multiplication and degrees are simple:
symprod <- function(A,B) sapply(1:ncol(B), function(j)sapply(1:nrow(A), function(i)rowcol(A[i,],B[,j]))) sympow <- function(A,n) { B <- A; for( i in seq_len(n-1) ) B <- symprod(B,A); B }
They create reliable (albeit awkward) expressions:
> A <- matrix(LETTERS[1:4],2,2) > diag(A) <- 0 > sympow(A,3) [,1] [,2] [1,] "((0)*(0)+(C)*(B))*(0)+((0)*(C)+(C)*(0))*(B)" "((0)*(0)+(C)*(B))*(C)+((0)*(C)+(C)*(0))*(0)" [2,] "((B)*(0)+(0)*(B))*(0)+((B)*(C)+(0)*(0))*(B)" "((B)*(0)+(0)*(B))*(C)+((B)*(C)+(0)*(0))*(0)"
Now let's talk about simplification. These strings can be parsed into real R expressions, because they conform to the R standard. Variables need not be defined because we will not evaluate expressions. In fact, I just want to analyze them in order to simplify the simplification.
Check out the feature below. It removes the extra parentheses, replaces the null value with zero, and removes the premises (in addition) that are zero:
simplify <- function(e) { if( mode(e) %in% c("name","numeric") ) return(e) if( as.character(e[[1]])=="+" ) { x <- simplify(e[[2]]) y <- simplify(e[[3]]) if( identical(x,0) ) return(y) if( identical(y,0) ) return(x) return(call("+", x, y)) } if( as.character(e[[1]])=="*" ) { x <- simplify(e[[2]]) if( identical(x,0) ) return(0) y <- simplify(e[[3]]) if( identical(y,0) ) return(0) return(call("*", x, y)) } if( as.character(e[[1]])=="(" ) { x <- simplify(e[[2]]) if( mode(x) %in% c("name","numeric") ) return(x) return(call("(", x)) } }
This function works with the call object. To use with strings we need
simplify_text <- function(s) deparse(simplify(parse(text=s)[[1]]))
Example:
> simplify_text("(x)+(0*(a+b))+(z)") [1] "x + z"
If you want, you can use it as a wrapper for rowcol :
rowcol <- function(row,col) simplify_text(paste(wrap(row),wrap(col),sep="*",collapse="+"))
Result:
> sympow(A,3) [,1] [,2] [1,] "0" "(C * B) * C" [2,] "(B * C) * B" "0"
Some other simplifications may be written, it depends on how you plan to work with them. But, if the input matrices are strings of valid expressions, the final result remains valid.
EDIT: another approach for rowcol :
Consider the following functions:
cellprod <- function(r, s) { z <- expand.grid(r,s, stringsAsFactors=FALSE) filter <- (z$Var1 != 0) & (z$Var2 != 0) paste(z$Var1[filter], z$Var2[filter], sep="*", collapse="+") } rowcol <- function(row,col) { x <- strsplit(row, "\\+") y <- strsplit(col, "\\+") L <- vapply(seq_along(x), function(i) cellprod(x[[i]],y[[i]]), character(1)) filter <- nzchar(L) if( ! any(filter) ) return("0") paste(L[filter], collapse="+") }
Using these functions instead of the functions indicated above, we can process matrices with expressions of the form x*y*z+a*b+f , i. e. the sum of the products in each cell. The functions automatically apply the distribution law, preserving the form (the sum of products), and also automatically removes zeros. Last example above:
> sympow(A,3) [,1] [,2] [1,] "0" "C*B*C" [2,] "B*C*B" "0"
No simplification required! Another example:
> A <- matrix(LETTERS[1:9],3,3) > B <- matrix(LETTERS[10:18],3,3) > A[2,3] <- 0 > A[3,2] <- 0 > B[1,3] <- 0 > B[3,1] <- 0 > A [,1] [,2] [,3] [1,] "A" "D" "G" [2,] "B" "E" "0" [3,] "C" "0" "I" > B [,1] [,2] [,3] [1,] "J" "M" "0" [2,] "K" "N" "Q" [3,] "0" "O" "R" > symprod(A,B) [,1] [,2] [,3] [1,] "A*J+D*K" "A*M+D*N+G*O" "D*Q+G*R" [2,] "B*J+E*K" "B*M+E*N" "E*Q" [3,] "C*J" "C*M+I*O" "I*R"