Sum of Antidiagonal of a Matrix

Sum of antidiagonal of a matrix

Using

m <- matrix(c(2, 3, 1, 4, 2, 5, 1, 3, 7), 3)

1) Reverse the rows as shown (or the columns - not shown), take the diagonal and sum:

sum(diag(m[nrow(m):1, ]))
## [1] 4

2) or use row and col like this:

sum(m[c(row(m) + col(m) - nrow(m) == 1)])
## [1] 4

This generalizes to other anti-diagonals since row(m) + col(m) - nrow(m) is constant along all anti-diagonals. For such a generalization it might be more convenient to write the part within c(...) as row(m) + col(m) - nrow(m) - 1 == 0 since then replacing 0 with -1 uses the superdiagonal and with +1 uses the subdiagonal. -2 and 2 use the second superdiagonal and subdiagonal respectively and so on.

3) or use this sequence of indexes:

n <- nrow(m)
sum(m[seq(n, by = n-1, length = n)])
## [1] 4

4) or use outer like this:

n <- nrow(m)
sum(m[!c(outer(1:n, n:1, "-"))])
## [1] 4

This one generalizes nicely to other anti-diagonals too as outer(1:n, n:1, "-") is constant along anti-diagonals. We can write m[outer(1:n, n:1) == 0] and if we replace 0 with -1 we get the super anti-diagonal and with +1 we get the sub anti-diagonal. -2 and 2 give the super super and sub sub antidiagonals. For example sum(m[c(outer(1:n, n:1, "-") == 1)]) is the sum of the sub anti-diagonal.

get the sum of diagonals and anti diagonals 2D N*N matrix using numpy

Use np.diag. Suppose you select element a[i, j]. Then,

>>> diagonal = np.diag(a, j-i)
>>> antidiagonal = np.diag(a[:, ::-1], N-j-1-i)
>>> np.sum(diagonal) + np.sum(antidiagonal)

This works, because j-i is the number of columns above the diagonal entry (i, i). So np.diag(a, j-i) correctly picks the diagonal corresponding to 8.

For the antidiagonal, I simply flip the array horizontally (by reversing the columns), and then run np.diag again. But now, the new column index is N-j-1, while the row index remains i.

If you find a[:, ::-1] unreadable, you could use np.fliplr(a) or np.flipud(a) instead, as Eric suggests.

Sum along diagonal and anti-diagonal lines in 2D array - NumPy / Python

you can use .diag like this:

import numpy as np

arr = np.array([[1, 0, 0], [1, 0, 0], [0, 1, 0]])

left_diag = [np.sum(np.diag(np.fliplr(arr), d)) for d in range(len(arr) - 1, -len(arr), -1)]
right_diag = [np.sum(np.diag(arr, d)) for d in range(len(arr) - 1, -len(arr), -1)]

print("left:", left_diag)
print("right:", right_diag)

Output:

left: [1, 1, 0, 1, 0]
right: [0, 0, 1, 2, 0]

it returns all the element in a diagonal of a given offset. to get all the offsets in the order you mentioned, we go from +2 to -2, then for each diagonal get the sum of elements.

to get the left diagonal we first flip arr using .fliplr

numpy sum antidiagonals of array

There is a trace function that gives the sum of a diagonal. You can specify the offset and 2 axes (0 and 1 are the defaults). And to get the antidiagonal, you just need to flip one dimension. np.flipud does that, though it's just [::-1,...] indexing.

Putting those together,

np.array([np.trace(np.flipud(array),offset=k) for k in range(-1,3)])

matches your new_array.

It still loops over the possible values of l (4 in this case). trace itself is compiled.

In this small case, it's actually slower than your double loop (2x3 steps). Even if I move the flipud out of the inner loop, it is still slower. I don't know how this scales for larger arrays.

Part of the problem with vectorizing this even further is that fact that each diagonal has a different length.

In [331]: %%timeit
array1 = array[::-1]
np.array([np.trace(array1,offset=k) for k in range(-1,3)])
.....:
10000 loops, best of 3: 87.4 µs per loop

In [332]: %%timeit
new_array = np.zeros([array.shape[0] + array.shape[1] - 1] + list(array.shape[2:]))
for i in range(2):
for j in range(3):
new_array[i+j] += array[i,j]
.....:
10000 loops, best of 3: 43.5 µs per loop

scipy.sparse has a dia format, which stores the values of nonzero diagonals. It stores a padded array of values, along with the offsets.

array([[12,  0,  0,  0],
[ 8, 13, 0, 0],
[ 4, 9, 14, 0],
[ 0, 5, 10, 15],
[ 0, 1, 6, 11],
[ 0, 0, 2, 7],
[ 0, 0, 0, 3]])
array([-3, -2, -1, 0, 1, 2, 3])

While that's a way of getting around the issue of variable diagonal lengths, I don't think it helps in this case where you just need their sums.

How to check if the terms on the anti diagonal of a matrix are the same?

Array indices in C are 0-based; thus, if your matrix is NxN, the indices for any element on the anti-diagonal will sum to N-1, not N.

Sum of diagonal elements in a matrix

Try this for summing your second diagonal:

sum(a[i][n-i-1] for i in range(n))

The inner loop accesses these entries:

>>> n = 3
>>> [(i, n-i-1) for i in range(n)]
[(0, 2), (1, 1), (2, 0)]

And the summed value of this diagonal for your sample matrix is:

>>> n = 3
>>> sum(a[i][n-i-1] for i in range(n))
19

The mistake in your code is to use the same expression for both dimensions:

a[n-i-1][n-i-1]

which will process the first diagonal again in reverse order [(2, 2), (1, 1), (0, 0)] giving you the same sum twice.

R Shiny - Extracting Anti-Diagonal elements in matrix using for-loops

Solved the issue by changing the codes to below:

for(i in 1:3) {
for(j in 3:1) {

my_table[,1] <- rev(my_input_matrix[i+(j-1)*3])[i]
my_table[,2] <- my_input_matrix[i+(j-1)*3][i]

}
}

Java add matrix antidiagonal elements

In your first example the loop ends as soon as j != 0, if t > 1 this means that it will end immediately, making no iterations at all.

How to find the sum of all anti-diagonals?

First note that outer can produce the matrix d without explicitly listing its elements.

matrix(c(0, 1, 2, 1, 2, 3, 2, 3, 4), 3)
#> [,1] [,2] [,3]
#> [1,] 0 1 2
#> [2,] 1 2 3
#> [3,] 2 3 4
outer(0:2, 0:2, `+`)
#> [,1] [,2] [,3]
#> [1,] 0 1 2
#> [2,] 1 2 3
#> [3,] 2 3 4

Created on 2022-03-24 by the reprex package (v2.0.1)

And use it in a function.

sumAntiDiag <- function(M){
nr <- nrow(M)
nc <- ncol(M)
d <- outer(seq.int(nr), seq.int(nc), `+`)
tapply(M, d, sum)
}

n <- 3
x <- c(0.85, 0.1, 0.05)
M <- matrix(NA, n, n);

for(i in 1:n){
for(j in 1:n){
M[i,j] = x[i] * x[j]
}}

sumAntiDiag(M)
#> 2 3 4 5 6
#> 0.7225 0.1700 0.0950 0.0100 0.0025

Created on 2022-03-24 by the reprex package (v2.0.1)



Related Topics



Leave a reply



Submit