# Off diagonal elements of Matrix

**URL:** https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169
**Category:** General Usage
**Created:** [June 10, 2020, 11:03pm UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169 "2020-06-10T23:03:22Z")
**Posts on this page:** 15
**Page:** 1

<div class="post-metadata">

### Author: ![jamblejoe](https://avatars.discourse-cdn.com/v4/letter/j/ee7513/32.png) [@jamblejoe](https://discourse.julialang.org/u/jamblejoe)
#### Post date: [June 10, 2020, 11:03pm UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/1 "2020-06-10T23:03:22Z")

</div>

Hi,  
what is the Julia-way of obtaining off-diagonal elements of a matrix flattend as a vector, e.g.

```julia
A = [1 2; 3 4]
offdiag(A) = [2, 3]

```

I stumbled across `diagind` but could not figure out how to do it neatly.  
Best,  
jamblejoe

EDIT: Better example:

```julia
A = [1 2 3; 4 5 6; 7 8 9]
offdia(A) = [2, 3, 4, 6, 7, 8]

```

EDIT2:

- Generic solution is the marked solution
- Faster solution for square matrices is [Off diagonal elements of Matrix - #8 by jamblejoe](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/8)
- non-allocating iterator is [Off diagonal elements of Matrix - #12 by jamblejoe](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/12)

EDIT3:

- flattening the matrix to a vector and then deleting the diagonal seems to work very fast as well, see [Off diagonal elements of Matrix - #13 by Seif\_Shebl](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/13)

---

<div class="post-metadata">

### Author: ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)
#### Post date: [June 10, 2020, 11:05pm UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/2 "2020-06-10T23:05:59Z")

</div>

For bigger matrices what order do you want?

---

<div class="post-metadata">

### Author: ![jamblejoe](https://avatars.discourse-cdn.com/v4/letter/j/ee7513/32.png) [@jamblejoe](https://discourse.julialang.org/u/jamblejoe)
#### Post date: [June 10, 2020, 11:09pm UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/3 "2020-06-10T23:09:40Z")

</div>

I do not care right now. I am just interested in the 2D case!

EDIT: Sorry, I should have mentioned that!

---

<div class="post-metadata">

### Author: ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)
#### Post date: [June 10, 2020, 11:11pm UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/4 "2020-06-10T23:11:12Z")

</div>

by 2D do you mean 2x2?

---

<div class="post-metadata">

### Author: ![jamblejoe](https://avatars.discourse-cdn.com/v4/letter/j/ee7513/32.png) [@jamblejoe](https://discourse.julialang.org/u/jamblejoe)
#### Post date: [June 10, 2020, 11:12pm UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/5 "2020-06-10T23:12:15Z")

</div>

No, I mean `Array{T, 2}`.

---

<div class="post-metadata">

### Author: ![L\_Adam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/l_adam/32/12086_2.png) [@L\_Adam](https://discourse.julialang.org/u/L_Adam)
#### Post date: [June 11, 2020, 2:14am UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/6 "2020-06-11T02:14:58Z")

</div>

quick and dirty way for `Array{T, 2}`

```julia
function offdiag(ma)
  m, n = size(ma)
  [ma[i, j] for i = 1:m, j = 1:n if i != j]
end 

```

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [June 11, 2020, 7:00am UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/7 "2020-06-11T07:00:06Z")

</div>

Or using the generalized indexing accessors,

```julia
function offdiag2(A::AbstractMatrix)
    [A[ι] for ι in CartesianIndices(A) if ι[1] ≠ ι[2]]
end 

```

which should work for indexes other than 1-based.

---

<div class="post-metadata">

### Author: ![jamblejoe](https://avatars.discourse-cdn.com/v4/letter/j/ee7513/32.png) [@jamblejoe](https://discourse.julialang.org/u/jamblejoe)
#### Post date: [June 11, 2020, 10:42am UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/8 "2020-06-11T10:42:28Z")

</div>

Thanks for all the answers so far, @L_Adam, @Tamas_Papp! In the initial post I ordered the matrix entries rowwise, but everybody correctly assumed columnwise ordering 😃

I came up with a quick and dirty way for 1-based indexing and quadratic matrices, which does not need an `if`-statement:

```julia
function offdiag(A::Matrix)
    @assert size(A)[1] == size(A)[2]
    D = size(A)[1]
    v = zeros(D*(D-1))
    for i in 1:D
        for j in 1:(i-1)
            v[(i-1)*(D-1)+j] = A[j,i]
        end
        for j in (i+1):D
            v[(i-1)*(D-1)+j-1] = A[j,i]
        end
    end
    v
end

```

I know from direct SIMD programming that conditions in your code can decrease performance gains from SIMD by a factor (2?). Would this apply here as well? Or is Julia smart enough or not using SIMD at all?

PS: In my code example, one has off course disable bounds checking to make automatic SIMD available.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [June 11, 2020, 10:49am UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/9 "2020-06-11T10:49:40Z")

</div>

> [@jamblejoe](#):
>
> Would this apply here as well?

I would suggest that you simply benchmark, eg with

> **[GitHub - JuliaCI/BenchmarkTools.jl: A benchmarking framework for the Julia...](https://github.com/JuliaCI/BenchmarkTools.jl/)**
>
> A benchmarking framework for the Julia language. Contribute to JuliaCI/BenchmarkTools.jl development by creating an account on GitHub.

---

<div class="post-metadata">

### Author: ![jamblejoe](https://avatars.discourse-cdn.com/v4/letter/j/ee7513/32.png) [@jamblejoe](https://discourse.julialang.org/u/jamblejoe)
#### Post date: [June 11, 2020, 10:53am UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/10 "2020-06-11T10:53:52Z")

</div>

My code without bounds checking

```julia
let
    n = 100
    A = rand(n,n)
    @benchmark offdiag($A)
end

BenchmarkTools.Trial: 
  memory estimate: 77.45 KiB
  allocs estimate: 2
  --------------
  minimum time: 7.667 μs (0.00% GC)
  median time: 8.602 μs (0.00% GC)
  mean time: 8.939 μs (2.83% GC)
  maximum time: 2.540 ms (99.43% GC)
  --------------
  samples: 10000
  evals/sample: 3

```

@L_Adam’s code

```julia
let
    n = 100
    A = rand(n,n)
    @benchmark offdiag1($A)
end

BenchmarkTools.Trial: 
  memory estimate: 256.78 KiB
  allocs estimate: 17
  --------------
  minimum time: 78.077 μs (0.00% GC)
  median time: 80.600 μs (0.00% GC)
  mean time: 82.971 μs (1.17% GC)
  maximum time: 13.512 ms (71.90% GC)
  --------------
  samples: 10000
  evals/sample: 1

```

and @Tamas_Papp’s code

```julia
let
   n = 100
   A = rand(n,n)
   @benchmark offdiag2($A)
end

BenchmarkTools.Trial: 
 memory estimate: 256.77 KiB
 allocs estimate: 17
 --------------
 minimum time: 66.708 μs (0.00% GC)
 median time: 69.133 μs (0.00% GC)
 mean time: 70.352 μs (0.00% GC)
 maximum time: 3.355 ms (0.00% GC)
 --------------
 samples: 10000
 evals/sample: 1

```

Are the benchmarks done correctly? If yes, then the non-bounds checking, non-conditional code for square matrices is roughly 10x faster.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [June 11, 2020, 11:09am UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/11 "2020-06-11T11:09:10Z")

</div>

Yes, the benchmarks look OK.

If you know something about the structure of the problem, you can of course do better than a filtered collection (which does not know the number of elements in the result _ex ante_, etc).

---

<div class="post-metadata">

### Author: ![jamblejoe](https://avatars.discourse-cdn.com/v4/letter/j/ee7513/32.png) [@jamblejoe](https://discourse.julialang.org/u/jamblejoe)
#### Post date: [June 11, 2020, 11:13am UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/12 "2020-06-11T11:13:49Z")

</div>

That is true. My code looks more like a C example, while yours is a nice, generic oneliner. And it is easy to turn it into an interator over the off-diagonal indices than allocating a new vector.

```julia
offdiag_iter(A) = (ι for ι in CartesianIndices(A) if ι[1] ≠ ι[2])

```

Thanks!

---

<div class="post-metadata">

### Author: ![Seif\_Shebl](https://avatars.discourse-cdn.com/v4/letter/s/eada6e/32.png) [@Seif\_Shebl](https://discourse.julialang.org/u/Seif_Shebl)
#### Post date: [June 11, 2020, 3:12pm UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/13 "2020-06-11T15:12:29Z")

</div>

Just for completeness, `deleteat!` is quite efficient and accepts a collection for indices. The indices of the diagonal elements are simply `1:n+1:n^2`. Compared to manual loops, it can even be 30% faster.

```julia
A = randn(1000,1000);

@btime offdiag($A); # with bounds checking turned off
  3.399 ms (2 allocations: 7.62 MiB)

@btime deleteat!(vec($A), 1:size(A,1)+1:size(A,1)^2);
  2.595 ms (8 allocations: 7.63 MiB)

```

---

<div class="post-metadata">

### Author: ![jamblejoe](https://avatars.discourse-cdn.com/v4/letter/j/ee7513/32.png) [@jamblejoe](https://discourse.julialang.org/u/jamblejoe)
#### Post date: [June 11, 2020, 5:32pm UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/14 "2020-06-11T17:32:12Z")

</div>

Thanks @Seif_Shebl! I thought that this approach would be the slowest and discarded it from the beginning. I am surprised 😃

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [June 12, 2020, 9:37am UTC](https://discourse.julialang.org/t/off-diagonal-elements-of-matrix/41169/15 "2020-06-12T09:37:28Z")

</div>

> [@jamblejoe](#):
>
> My code looks more like a C example, while yours is a nice, generic oneliner.

The typical Julia solution is usually writing a generic catch-all method, and adding specialized methods when faster solutions are available for specific types.

This happens for dense matrices as in your example, but eg triangular and banded matrices could also benefit from specialized code. That said, for a one-off application this is probably overkill.
