Jürg W. Spaak
Jürg W. Spaak

Reputation: 2149

vectoriced norm/matrix multiplication

I have a norm that is described by the matrix sigma

sigma <- matrix(c(1,0.5,0,0.5,1,0,0,0,1),3,3))

To compute the norm of a vector I compute

t(x) %*% sigma %*% x

which works fine for a vector e.g. x = 1:3.

However i want to compute the norm of many vectors at the same time, that is I have

x <- t(matrix(rep(1:3, 10),3,10))

(of course filled with different entries).

Is there a way to compute the norm of each vector simultanuously? I.e. something like

lapply(1:10, function(i) t(x[i,]) %*% sigma %*% x[i,])

Upvotes: 0

Views: 139

Answers (3)

jogo
jogo

Reputation: 12569

You can do:

sigma <- matrix(c(1,0.5,0,0.5,1,0,0,0,1),3,3)
x <- t(matrix(rep(1:3, 10),3,10))

mynorm <- function(x, sig) t(x) %*% sig %*% x
apply(x, 1, mynorm, sig=sigma)

Here is a variant with tcrossprod():

mynorm <- function(x, sig) tcrossprod(x, sig) %*% x
apply(x, 1, mynorm, sig=sigma)

And here is the benchmark (including variants of the solution from compute only diagonals of matrix multiplication in R , thanks to @Benjamin for the link):

mynorm1 <- function(x, sig) t(x) %*% sig %*% x
mynorm2 <- function(x, sig) tcrossprod(x, sig) %*% x

microbenchmark(n1=apply(x, 1, mynorm1, sig=sigma), 
               n2=apply(x, 1, mynorm2, sig=sigma), 
               n3 = colSums(t(x) * (sigma %*% t(x))),
               n4 = rowSums(x * t(sigma %*% t(x))),
               n5 = rowSums(x * (x %*% t(sigma) )),
               n6 = rowSums(x * tcrossprod(x, sigma)),
               Eugen1 = diag(x %*% sigma %*% t(x)),
               Eugen2 = diag(x %*% tcrossprod(sigma, x)),
               unit="relative")

Upvotes: 3

EugenR
EugenR

Reputation: 176

What do you think about this simple matrix multiplication:

 diag(t(x) %*% sigma %*% x)

Edit: after the matrix multiplications you need the diagonal (of course).

Then it is faster then solutions with apply

Upvotes: 2

Benjamin Christoffersen
Benjamin Christoffersen

Reputation: 4841

This should do

> sigma <- matrix(c(1,0.5,0,0.5,1,0,0,0,1),3,3)
> x <- t(matrix(rep(1:30, 10),3,10))
> 
> # should give
> t(x[1, ]) %*% sigma %*% x[1, ]
     [,1]
[1,]   16
> t(x[2, ]) %*% sigma %*% x[2, ]
     [,1]
[1,]   97
> 
> # which you can get by
> rowSums((x %*% sigma) * x)
 [1]   16   97  250  475  772 1141 1582 2095 2680 3337

Upvotes: 2

Related Questions