I'm trying to define a function manipulating matrices of strings in R.
{+,*} MATRICES MULTIPLICATION
The {+,*}-product of two square matrices A and B of dimension n is a matrix C defined by the elements: Ci,j = Sumk=1,...,nAi,k * Bk,j.
For example, consider the matrix M <- matrix(c(a,b,0,0,c,d,0,0,e),3,3)
. Then M times M is M <- matrix(c(a^2,a*b+b*c,b*d,0,c^2,c*d+d*e,0,0,e^2),3,3)
.
{c(,),paste0(,)} MATRICES MULTIPLICATION
The rule of this operation I would like to implement are the same of the previous stated multiplication with the essential mutation that the sum should be a concatenation and the product should be a paste. In other words, where in the previous formula we found a+b
, now the output should be "c(a,b)", and when we found a*b
, now we should read this as paste0(a,b)
.
Some of the usual properties have to be respescted, namely the distributive properties and the 0 element properties. Hence, if a <- c("q",0,"w")
and b <- c("e")
then a*b <- c("qe",0,"we")
(and we should freely forget the 0 element, dropping it as it won't affect the computation.
Moreover, we are multiplying equaldimensioned matrices, hence each element Ci,j = Sumk=1,...,nAi,k * Bk,j is now to be read as c("A[i,1]B[1,j]",...,"A[i,n]B[n,j]")
.
For semplicity sakeness, let's consider B always a simple matrix, meaning that each of its elements are atomic string, and not concatenation of string (the generalization is a subsequent step).
Let's give an example. Let A <- matrix(c("a","b",0,0,"c","d",0,0,"e"),3,3)
, then mult(A,A) = matrix(c("aa",c("ab","bc"),"bd",0,"cc",c("cd","de"),0,0,"ee"),3,3)
and mult(mult(A,A),A) = matrix(c("aaa",c("aab","abc","bcc"),c("abd","bcd","bde"),0,"ccc",c("ccd","cde","dee"),0,0,"eee"),3,3)
.
PARTIAL (NOT WORKING) IMPLEMENTATION
Consider as input a couple of nxn matrices M , N with whether 0 or array of strings c(s1,s2,...) as i,j elements. As output I would like to have a matrix MN = M x N where the multiplication is defined in analogy with the symbolic multiplication:
MNi,j = 0 if Mi,. or N.,j is 0
MNi,j = paste(Mi,.,N.,j) otherwise (using the distributive property of paste()
)
I gave a (wrong, does not check properly the zeros) definition of the base row/column paste function as
MijPaste <- function(Row,Col){
if(Col[1]=="0"){
Mij <- 0
} else if(Row[1]=="0"){
Mij <- 0
} else
Mij <- paste(Row,Col,sep="")
return(Mij)
}
I've not been able to go from this step to a proper definition of the multiplication function, as the element Mij that I would like to insert inside the matrix are not of the right dimension. And hence I get a number of items to replace is not a multiple of replacement length
error. My current implementation is:
# define the dimension of the matrix, here for example 3
dim <- 3
# define the Multiplication function as an iteration of the MijPaste function
Mult <- function(M1,M2){
#allocate a matrix of dimension nxn
M <- matrix(0,dim,dim)
#for each element i,j define it as the MijPaste of row i column j
for(i in 1:dim){
for(j in 1:dim){
stringi <- M1[i,]
stringj <- M2[,j]
M[i,j] <- MijPaste(stringi,stringj)
}
}
return(M)
}
The code doesn't work. I could probably change the matrix into a multidimensional array, but I would like the output to be usable as a matrix for further multiplication (for example to defin (MxN)xC).
How can I do?
Thank you!
P.S. You can test the code using a simple example matrix
Matr <- matrix(c("11","12","13","21","22","23","31","32","33"),dim,dim)
and running
Mult(Matr,Matr)
You can use paste
directly with the matrices, if you set the dimensions manually:
MN <- matrix(paste(M, N, sep=""), nrow=nrow(M), ncol=ncol(M))
Now filter the zeros and replace:
MN[(M==0) | (N==0)] <- 0
EDIT: the pointwise product shown above is NOT what the OP wants.
As I said in the comment, you can fix your function adding collapse=""
to your first function. I get the following results:
> M <- matrix(LETTERS[1:9],3,3)
> N <- matrix(LETTERS[10:18],3,3)
> M
[,1] [,2] [,3]
[1,] "A" "D" "G"
[2,] "B" "E" "H"
[3,] "C" "F" "I"
> N
[,1] [,2] [,3]
[1,] "J" "M" "P"
[2,] "K" "N" "Q"
[3,] "L" "O" "R"
> Mult(M,N)
[,1] [,2] [,3]
[1,] "AJDKGL" "AMDNGO" "APDQGR"
[2,] "BJEKHL" "BMENHO" "BPEQHR"
[3,] "CJFKIL" "CMFNIO" "CPFQIR"
As you can see, your function matches the elements in matrices M
and N
before pasting.
If you want to keep the elements of each matrix together, you can use these two lines:
> coll <- function(x)paste(x,collapse="")
> outer(apply(M,1,coll),apply(N,2,coll),paste0)
[,1] [,2] [,3]
[1,] "ADGJKL" "ADGMNO" "ADGPQR"
[2,] "BEHJKL" "BEHMNO" "BEHPQR"
[3,] "CFIJKL" "CFIMNO" "CFIPQR"
Of course, you have to insert the zeros manually after this.