# Checking if a list of vectors are all identical

**URL:** <https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215>\
**Category:** Performance\
**Tags:** arrays\
**Created:** [February 14, 2024, 5:33pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215 "2024-02-14T17:33:13Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Gus\_Hart](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gus_hart/32/6987_2.png) [@Gus\_Hart](https://discourse.julialang.org/u/Gus_Hart)\
**Post date:** [February 14, 2024, 5:33pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/1 "2024-02-14T17:33:13Z")

</div>

(Looking for the most idiomatic way to solve this problem. It’s inside several nested loops.)

I have a situation where I have two lists of 3-vectors. Often these two lists are identical except for displacement. (One set of points is merely a shifted copy of the other.) To check for identity, I just subtract them and then check to see that the component-wise difference is the same for all vectors. So the difference between two sets of vectors might be something like this (just a MWE, not realistic)

```julia
julia> t
4-element Vector{Vector{Float64}}:
 [0.1, 0.2, 3.3]
 [0.2, -0.2, 1.0]
 [0.3, 0.25, -1.0]
 [-0.1, -0.2, 0.3]

julia> s
4-element Vector{Vector{Float64}}:
 [-0.1, 0.5, 4.6]
 [0.0, 0.1, 2.3]
 [0.1, 0.55, 0.3]
 [-0.3, 0.1, 1.6]

julia> diffs=t-s
4-element Vector{Vector{Float64}}:
 [0.2, -0.3, -1.2999999999999998]
 [0.2, -0.30000000000000004, -1.2999999999999998]
 [0.19999999999999998, -0.30000000000000004, -1.3]
 [0.19999999999999998, -0.30000000000000004, -1.3]

```

So then I check to see that each difference vector matches the others by:

```julia
julia> all([diffs[1]≈i for i in diffs[2:end]])

```

Not sure if this is the best way to do this. Is there a more idiomatic way? It seems verbose with the list comprehension…

(I could perhaps store the points as columns in a matrix instead of as a vector of vectors…)

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [February 14, 2024, 5:53pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/2 "2024-02-14T17:53:11Z")

</div>

If allocations/performance don’t matter, I propose

```julia
diffs = t-s
sum(sum.(diff(diffs))) ≈ 0

```

but not sure whether this achieves the maximal clarity 😆

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [February 14, 2024, 6:44pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/3 "2024-02-14T18:44:12Z")

</div>

only slightly better:

```julia
julia> diffs = t-s;

julia> all(≈(first(diffs)), diffs)
true

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [February 14, 2024, 7:04pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/4 "2024-02-14T19:04:38Z")

</div>

> [@Gus\_Hart](#):
>
> `all([diffs[1]≈i for i in diffs[2:end]])`

First of all, remove the brackets:

```julia
all(diffs[1]≈i for i in diffs[2:end])

```

to avoid (one of) the redundant allocation(s).

In general, though I would try to avoid subtracting all those vectors, don’t create `diffs` in the first place, instead iterate, comparing subtractions on the fly. Ideally, there should be zero allocations for this.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [February 14, 2024, 8:15pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/5 "2024-02-14T20:15:44Z")

</div>

> [@DNF](#):
>
> instead iterate, comparing subtractions on the fly

For example:

```julia
all(tᵢ - sᵢ ≈ t[1] - s[1] for (tᵢ, sᵢ) in zip(t,s))

```

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [February 14, 2024, 8:19pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/6 "2024-02-14T20:19:05Z")

</div>

```julia
t .- [t[1]] ≈ s .- [s[1]] 

```

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [February 14, 2024, 8:28pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/7 "2024-02-14T20:28:59Z")

</div>

@rocco_sprmnt21, are you sure it is computing the same thing?  
From the docs, it looks more like it uses the norm:  
 ![gif](https://global.discourse-cdn.com/julialang/original/3X/f/3/f36467a4f98fe0899ade0e7c59b1c80a48d4ad55.gif)

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [February 14, 2024, 8:39pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/8 "2024-02-14T20:39:03Z")

</div>

> [@rafael.guerra](#):
>
> `all(tᵢ - sᵢ ≈ t[1] - s[1] for (tᵢ, sᵢ) in zip(t,s))`

Using `≈` elementwise like this may be unreliable. Approximate comparison `≈` is not something you can use blindly — you are asking that the difference should be small, but you should always think “small compared to what”?

The problem with doing approximate comparison elementwise is that `a ≈ b` checks by default that `|a - b|` is small compared to `|a|` or `|b|`, and by default to about 8 digits. But what if `t[1] - s[1]` happens to be zero (or nearly zero)? Then `tᵢ - sᵢ ≈ t[1] - s[1]` will almost always be `false`, because nothing is small compared to zero (except for zero itself).

In your case, it’s a tricky question — what is the right “yardstick” to compare to? If you know something from your problem (e.g. some overall scale of your coordinate system), then you can use it to pass an absolute tolerance `atol` to [`isapprox` (the same function as `≈`)](https://docs.julialang.org/en/v1/base/math/#Base.isapprox). Otherwise, you would want to compute some relevant scale, e.g. the diameter of your point cloud.

(There’s also the delicate question of choosing an appropriate tolerance. `atol = lengthscale * small`, but what is `small`? `√eps() ≈ 1.5e-8` is the default relative tolerance `rtol` for `≈`, corresponding to half the significant digits, because this is a reasonable rule of thumb for unit tests: small enough to catch most bugs, but large enough to be resilient to roundoff errors. But if your application is not a unit test, your needed tolerance may be very different.)

> I have a situation where I have two lists of 3-vectors

Working with this data structure will probably be _much, much faster_ if you use arrays of `SVector{3,Float64}` from StaticArrays.jl. Then you can use natural vector operations, like subtracting two vectors, and it will be (a) allocation-free and (b) unrolled by the compiler. See the [performance tips](https://docs.julialang.org/en/v1/manual/performance-tips/#Consider-StaticArrays.jl-for-small-fixed-size-vector/matrix-operations).

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [February 14, 2024, 8:50pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/9 "2024-02-14T20:50:27Z")

</div>

Thanks Steve. Would something like this be better? (\*edited using: `atol`)

```julia
all(isapprox(tᵢ - sᵢ, t[1] - s[1], atol=1e-3) for (tᵢ, sᵢ) in zip(t,s))

```

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [February 14, 2024, 8:56pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/10 "2024-02-14T20:56:44Z")

</div>

How does:

```julia
all(s .+ Ref(mean(t-s)) .≈ t)

```

look?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [February 14, 2024, 8:58pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/11 "2024-02-14T20:58:17Z")

</div>

> [@rafael.guerra](#):
>
> Thanks Steve. Would something like this be better? `all(isapprox(tᵢ - sᵢ, t[1] - s[1], rtol=1e-3) for (tᵢ, sᵢ) in zip(t,s))`

No, because you are passing only a relative tolerance `rtol`. That means it will still probably fail if `t[1] - s[1]` happens to be nearly zero.

> [@rafael.guerra](#):
>
> (\*edited using: `atol`)

Yes, using `atol` is safer, but requires you to pick a reasonable `atol`, and that depends on the problem because **`atol` is dimensionful**.

For example, suppose your vectors represent positions of stars in the galaxy, with coordinates measured in meters. Then `atol = 1e-3` (1mm) is probably a ridiculously small tolerance. On the other hand, if you are doing atomic physics with distances in meters, where the typical scale is [angstroms](https://en.wikipedia.org/wiki/Angstrom), then `atol = 1e-3` is a ridiculously large tolerance.

> [@Dan](#):
>
> How does: `all(s .+ Ref(mean(t-s)) .≈ t)` look?

This is still likely to fail if any element of `t` happens to be zero or nearly zero.

Note, by the way, that `≈` works perfectly well on arrays, or arrays of arrays (anything with a `norm`), so using `≈` with `all` is generally unnecessary (and more susceptible to scaling problems). You can just do `s .+ Ref(mean(t-s)) ≈ t` (no dot on the `≈`), which is more robust although it will still be problematic if `norm(t) == 0` (maybe that is less likely … but ultimately you should still be thinking about an appropriate problem-dependent `atol`).

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [February 14, 2024, 9:38pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/12 "2024-02-14T21:38:08Z")

</div>

I’m not sure I understand the question/observation. I definitely don’t understand the reference to the norm.  
What I wrote (which is ultimately equivalent to the other proposed forms. I don’t know if from a numerical point of view it is more robust to Stevenj’s observations) is based on the fact that if the two vectors are equivalent under a translation, then translating them into so that the first element of both goes to the origin, the two vectors must “overlap” element by element

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [February 14, 2024, 9:53pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/13 "2024-02-14T21:53:43Z")

</div>

> [@stevengj](#):
>
> This is still likely to fail if any element of `t` happens to be zero or nearly zero.

🤦 Yes, I didn’t fix the problem.  
But:

```julia
using LinearAlgebra

all(s - t .≈ Ref(mean(s - t)))

```

might fix it: `isapprox` defaults to use `norm` when comparing vectors, and `mean(s-t)`'s norm is a good measuring yardstick for how small the dispersion of `s - t` should be (limited through `rtol`).

But I’m still not sure enough. Doing a more explicit and simpler test would avoid bugs.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [February 14, 2024, 10:24pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/14 "2024-02-14T22:24:03Z")

</div>

> [@Dan](#):
>
> ```julia
> all(s - t .≈ Ref(mean(s - t)))
> 
> ```
> 
> might fix it

Still seems wrong. The mean could easily be zero, no?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [February 14, 2024, 10:30pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/15 "2024-02-14T22:30:04Z")

</div>

> [@rocco\_sprmnt21](#):
>
> `t .- [t[1]] ≈ s .- [s[1]] `

> [@rocco\_sprmnt21](#):
>
> I don’t know if from a numerical point of view it is more robust to Stevenj’s observations) is based on the fact that if the two vectors are equivalent under a translation, then translating them into so that the first element of both goes to the origin, the two vectors must “overlap” element by element

Your code is better than elementwise — as I wrote [above](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/11), `≈` is generally better to do on whole arrays — the more values the better to gauge the correct overall scale. But the problem with your code is still the implicit relative tolerance on the `≈`, which can make the approximate comparison fail unexpectedly.

For example, your code returns `false` in this case:

```julia
julia> s = [1, 1, 1]; t = [1, 1, 1 + 1e-15]
3-element Vector{Float64}:
 1.0
 1.0
 1.000000000000001

julia> t .- [t[1]] ≈ s .- [s[1]]
false

```

even though `s ≈ t` to 15 digits. (It is giving a correct answer to the question you asked! If you compare `[0,0,1e-15]` to `[0,0,0]`, they don’t match in the third component to _any_ significant digits. You have given `isapprox` no other yardstick by which to say that `1e-15` is small in this problem.)

To get a more reliable comparison, you really need to think about a problem-specific `atol`.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [February 14, 2024, 11:11pm UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/16 "2024-02-14T23:11:16Z")

</div>

Assuming that `1e-3` is a good yardstick for the OP’s data, then your preference would be to modify @rocco_sprmnt21’s snippet as follows?

```julia
isapprox(t .- [t[1]], s .- [s[1]], atol=1e-3)

```

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [February 15, 2024, 1:53am UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/17 "2024-02-15T01:53:02Z")

</div>

Oh this looks pretty sweet and works even in some edge cases:

```julia
julia> diff(s) ≈ diff(t)
true

```

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [February 15, 2024, 2:09am UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/18 "2024-02-15T02:09:17Z")

</div>

If they’re all three vectors, then you might want to use a static length structure for them all… and then that lends itself nicely to being reinterpreted as a matrix… and then there’s Linear Algebra fun to be had with linear dependencies. 🙂

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [February 15, 2024, 7:33am UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/19 "2024-02-15T07:33:40Z")

</div>

I’m afraid not. The counterexample proposed by Stevengj also applies to this nice solution.  
This leads me to advance the following conjecture: for every proposed solution, in the “numerical context” there is always a counterexample that makes it fail.

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [February 15, 2024, 7:37am UTC](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215/20 "2024-02-15T07:37:21Z")

</div>

Now I think I understand your previous observation. I was looking for an answer to the OP’s request for an “idiomatic solution”, but I didn’t take the numerical aspects into consideration at all (not voluntarily: just out of ignorance. I don’t have any experience with software for “real” uses).

[Next page](https://discourse.julialang.org/t/checking-if-a-list-of-vectors-are-all-identical/110215.md?page=2)
