Unit test equality for arrays?


#1

I am trying to use unit test to test the equality of two arrays, wheres the following test:
@test [2.36248e-314, 2.36248e-314] ≈ [0.0, 0.0]
would fail. The two entries in the vector, if compared separately with the same method, would pass the equality test. Is there an extended unit test for equality for arrays in julia?


#2

What do you mean here?

julia> 2.36248e-314 ≈ 0.0
false

#3

There is (although as @kristoffer.carlsson pointed out, the two arguments are not \approx individually). You can see which method is being called for any function call in Julia with @which:

julia> @which [2.36248e-314, 2.36248e-314] ≈ [0.0, 0.0]
isapprox(x::AbstractArray, y::AbstractArray) in Base.LinAlg at linalg/generic.jl:1297

julia> @which 2e-314 ≈ 0.0
isapprox(x::Number, y::Number) in Base at floatfuncs.jl:205

and you can open the relevant line in your editor with @edit:

julia> @edit [2.36248e-314, 2.36248e-314] ≈ [0.0, 0.0]

#4

To just test elementwise you could use dot syntax

julia> [1.0, 1e9] ≈ [0.0, 1e9]
true

julia> all([1.0, 1e9] .≈ [0.0, 1e9])
false

#5

If you want to test that an array is approximately zero, you need to either pass an absolute tolerance (atol keyword) to isapprox (you can also do @test x ≈ y atol=sometolerance in 0.7) or just test norm(x) ≤ sometolerance.

Without an atol keyword, only tests that the relative error is small, and in particular that about half of the significant digits match. 2.36248e-314 ≈ 0.0 is false because none of the significant digits match.

The default atol is zero because there is no sensible way to pick a nonzero default absolute tolerance without additional information. The problem is that the absolute tolerance depends on the overall scale (it is “dimensionful”): the result of x ≈ y shouldn’t change if you change the units/scaling, e.g. if you multiply both x and y by 1e18.

(I feel like this is a FAQ …)


#6

I am actually surprised by this. I tested with 0.9999999999 and 1, which returns true, so I thought there is some default tolerance for equality testing.


#7

As Steven described, there exists a default relative tolerance.

Copying the docstring here:

 isapprox(x, y; rtol::Real=sqrt(eps), atol::Real=0, nans::Bool=false, norm::Function)

  Inexact equality comparison: true if norm(x-y) <= atol + rtol*max(norm(x), norm(y)). The default atol is zero and the default rtol depends on the types of x and y. The
  keyword argument nans determines whether or not NaN values are considered equal (defaults to false).

#8

Why didn’t isapprox(x::AbstractArray, y::AbstractArray) disappear as part of the . broadcasting deprecations?


#9

Because it does something different from the dotted version.

Similar reason why *(::Matrix, ::Matrix) didn’t get removed.