[R] Summing up diagonals w/o for-loop

2008-02-26 Thread Camarda, Carlo Giovanni
Dear R-users,

is there any way to sum up the elements of the diagonals of a matrix
without using a for-loop? While there is a simple way over rows and
columns, I don't see a straightforward multiplication for the diagonals,
am I too demanding? Or, more likely, I'm lack some algebra trick? Is
there any R-function that can deal with this problem w/o loop?

Actually I would need to sum up just the upper diagonals.

Here a simple, but general, example for presenting the problem. 

Thanks in advance for any help,
Carlo Giovanni Camarda

m - 7
n - 5
mat - matrix(1:35, n, m)
ones.r - rep(1,n)
ones.c - rep(1,m)
# sum over the rows
sum.r - mat%*%ones.c
# sum over the cols
sum.c - t(mat)%*%ones.r
# sum over the diags
sum.d - numeric(m+n-1)
sum.d[1] - mat[n,1]
sum.d[m+n-1] - mat[1,m]
for(i in 2:n){
sum.d[i] - sum(diag(mat[(n+1-i):n,1:i]))
}
for(i in 2:(m-1)){
sum.d[i+n-1] - sum(diag(mat[,i:m]))
}



--
This mail has been sent through the MPI for Demographic ...{{dropped:10}}

__
R-help@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.


Re: [R] Summing up diagonals w/o for-loop

2008-02-26 Thread Marc Schwartz
Camarda, Carlo Giovanni wrote:
 Dear R-users,

 is there any way to sum up the elements of the diagonals of a matrix
 without using a for-loop? While there is a simple way over rows and
 columns, I don't see a straightforward multiplication for the diagonals,
 am I too demanding? Or, more likely, I'm lack some algebra trick? Is
 there any R-function that can deal with this problem w/o loop?

 Actually I would need to sum up just the upper diagonals.

 Here a simple, but general, example for presenting the problem.

 Thanks in advance for any help,
 Carlo Giovanni Camarda

 m- 7
 n- 5
 mat- matrix(1:35, n, m)
 ones.r- rep(1,n)
 ones.c- rep(1,m)
 # sum over the rows
 sum.r- mat%*%ones.c
 # sum over the cols
 sum.c- t(mat)%*%ones.r
 # sum over the diags
 sum.d- numeric(m+n-1)
 sum.d[1]- mat[n,1]
 sum.d[m+n-1]- mat[1,m]
 for(i in 2:n){
  sum.d[i]- sum(diag(mat[(n+1-i):n,1:i]))
 }
 for(i in 2:(m-1)){
  sum.d[i+n-1]- sum(diag(mat[,i:m]))
 }



If we have 'mat':

  mat
  [,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,]16   11   16   21   26   31
[2,]27   12   17   22   27   32
[3,]38   13   18   23   28   33
[4,]49   14   19   24   29   34
[5,]5   10   15   20   25   30   35


You can use:

  rowSums(mat)
[1] 112 119 126 133 140

and:

  colSums(mat)
[1]  15  40  65  90 115 140 165


for your initial steps, rather than the matrix multiplication. See 
?colSums for more information.

There may be a better way than this, but one approach for the diagonals 
in the order you want is to split() the matrix into it's constituent 
diagonals based upon subsetting using the row() and col() values. This 
yields a list:

  split(mat, col(mat) - row(mat))
$`-4`
[1] 5

$`-3`
[1]  4 10

$`-2`
[1]  3  9 15

$`-1`
[1]  2  8 14 20

$`0`
[1]  1  7 13 19 25

$`1`
[1]  6 12 18 24 30

$`2`
[1] 11 17 23 29 35

$`3`
[1] 16 22 28 34

$`4`
[1] 21 27 33

$`5`
[1] 26 32

$`6`
[1] 31



Then we can use sapply() to sum() over the list elements:

  sum.d
  [1]   5  14  27  44  65  90 115 100  81  58  31

  sapply(split(mat, col(mat) - row(mat)), sum)
  -4  -3  -2  -1   0   1   2   3   4   5   6
   5  14  27  44  65  90 115 100  81  58  31

If you want to sum the diagonals the other way replace the '-' in the 
second argument in split() with a '+'.


See ?split, ?sapply, ?row and ?col for more information.

HTH,

Marc Schwartz

__
R-help@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.