Search code examples
rmatrixmatrix-multiplication

How to multiply two matrices replacing * with a different operator


Consider:

Library(Matrix)
A <- matrix(c(1,2,3,4,5,6), nrow=3)
A
t(A)
A %*% t(A)

This gives:

#  A
#      [,1] [,2]
#  [1,]    1    4
#  [2,]    2    5
#  [3,]    3    6
#
#  t(A)
#       [,1] [,2] [,3]
#  [1,]    1    2    3
#  [2,]    4    5    6
#  
#  A %*% t(A)
#       [,1] [,2] [,3]
#  [1,]   17   22   27
#  [2,]   22   29   36 <---
#  [3,]   27   36   45

Q: I would like to replace the multiplication * by a different binary operator, for example min or max, preferably in R base.

Using matrix multiplication element 2,3 in the result gives 2 * 3 + 5 * 6 = 36.

Instead I would like to have:

  • min(2,3) + min(5,6) = 7, or
  • max(2,3) + max(5,6) = 9

Solution

  • Probably you are after the following things

    > a <- asplit(A, 1)
    
    > outer(a, a, \(...) mapply(\(...) sum(pmin(...)), ...))
         [,1] [,2] [,3]
    [1,]    5    5    5
    [2,]    5    7    7
    [3,]    5    7    9
    
    > outer(a, a, \(...) mapply(\(...) sum(pmax(...)), ...))
         [,1] [,2] [,3]
    [1,]    5    7    9
    [2,]    7    7    9
    [3,]    9    9    9
    

    A more efficient solution (but will have more lines of code) is using combn. For example:

    • for the min operator
    > m <- diag(rowSums(A))
    
    > m[lower.tri(m)] <- combn(a, 2, \(...) sum(do.call(pmin, ...)))
    
    > (out <- (m + t(m)) - diag(diag(m)))
         [,1] [,2] [,3]
    [1,]    5    5    5
    [2,]    5    7    7
    [3,]    5    7    9
    
    • for the max operator
    > m <- diag(rowSums(A))
    
    > m[lower.tri(m)] <- combn(a, 2, \(...) sum(do.call(pmax, ...)))
    
    > (out <- (m + t(m)) - diag(diag(m)))
         [,1] [,2] [,3]
    [1,]    5    7    9
    [2,]    7    7    9
    [3,]    9    9    9