How to query elements in a matrix diagonal to a given point

I’m wondering if there’s an efficient way to return all of the elements in a matrix that are diagonal to some starting point. For example, given the following matrix:

julia> A = [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16]
4×4 Array{Int64,2}:
  1   2   3   4
  5   6   7   8
  9  10  11  12
 13  14  15  16

If I want to query the matrix to return all elements that are diagonal to the number 7 (so A[2,3]), I should get back [2, 12, 4, 10, 13]. If I query the matrix at point A[4,4] (where 16 is), I would want to get back [1,6,11].

Is there a package that already does something like this or is this going to take a custom function?

EDIT: The matrices that I need this for will always be square

How about Diagonal(A)? You will need to put using LinearAlgebra first to bring in the package. In general, you might want to read Linear Algebra · The Julia Language

Hi Oscar. So it looks like this simply converts my matrix into a Diagonal matrix, keeping only the main diagonal. Am I missing something here? Can I use this to get all elements that are diagonal and anti-diagonal to some specific point?

I think you are definitely going to need to write your own function for that.

1 Like

I think you are definitely going to need to write your own function for that.

This won’t be happening at this hour on a Sunday night :laughing: I’ll take a crack at it tomorrow and if I come up with something decent I’ll post here :grinning:

Oh, sorry, I misread your question.

Does this work? It’s not optimized, but should be decent

function diagonals(A::Matrix{T},i,j) where T
       s = size(A)
       out = Vector{T}()
       for row in 1:s[1]
           if i == row
               continue
           end
           col1 = j - (i-row)
           if 1 <= col1 <= s[2]
               append!(out, A[row,col1])
           end
           col2 = j + (i-row)
           if 1 <= col2 <= s[2]
               append!(out, A[row,col2])
           end
       end
       return out
   end
2 Likes

Might make sense to exploit the strideness:

julia> function diagonals(A, i, j)
          n = size(A,1)
          s = (j-1)*n + i
          [A[s-(n+1):-(n+1):begin]; A[s+(n+1):(n+1):end]; A[s+(n-1):(n-1):end-1]; A[s-(n-1):-(n-1):begin+1]]
       end
diagonals (generic function with 1 method)

julia> diagonals(A, 2,3)
5-element Array{Int64,1}:
  2
 12
  4
 10
 13

Though the code still needs to be fixed for edge cases:

julia> diagonals(A,4,4) # this is wrong
7-element Array{Int64,1}:
 11
  6
  1
  4
  7
 10
 13
2 Likes

Alright, here’s what I came up with. It performs horrendously compared to either of the solutions posted by @Oscar_Smith and @dlfivefifty and it deviates a bit from the stated objective as it returns two different vectors, both of which include the element at the query starting point. About the only thing that it has going for it is that it’s a one-liner:

diagonals(A, i, j) = diag(A,j-i), diag(reverse(A,dims=1),(i+j)-(size(A,1)+1))

julia> A = [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16]
4×4 Array{Int64,2}:
  1   2   3   4
  5   6   7   8
  9  10  11  12
 13  14  15  16

julia> diagonals(A,3,4)
([2, 7, 12], [15, 12])

julia> diagonals(A,2,2)
([1, 6, 11, 16], [9, 6, 3])
1 Like