Arrays to vector conversion

Hello all,

I am trying to write a function where i have to compare two quantities, the simplified representation of the problem where i am stuck is as

I get these type of two quantities as follows:

a = [[9], [8]]
b = [9.0121, 9.008]

if isapprox(a, b; atol=1e-5)
   print ("done")
else
  print("not done")
end

I am not able to compare “a” and “b” and it is giving me this error DimensionMismatch: dimensions must match: a has dims (Base.OneTo(0),), b has dims (Base.OneTo(2),), mismatch at 1

I guess i have to convert “b” such that its shape is similar to “a”, any idea how can i do that? thank you

You could use: reduce(vcat,a), to convert a to a vector like b, which seems simpler than the other way around.

2 Likes

If I run your code I don’t get a DimensionMismatch error. Instead I get ERROR: MethodError: no method matching -(::Vector{Int64}, ::Float64).

It’s not just a problem of different shapes, but of very different types. Note that [[9], [8]] In Julia is not a matrix with two rows like in Numpy. It’s a vector that contains two vectors. If that’s really what you want, and if you know that all the vectors in a have one element, you can do isapprox(only.(a), b; atol=1e-5). Here only.(a) will collect the single elements of [9] and [8] into a new vector [9, 8].

1 Like

Something like

all(isapprox(x, y, tol) for (x, y) in zip(flatten(a), flatten(b))))

flatten is from Iterators, and is the key. It will unroll nested arrays to any depth, spitting out scalars, without allocating intermediate arrays.

Warning: untested and written on a phone.

A merge of @sijo and @DNF solutions, that is short and non-allocating:

all(isapprox(only(x), y; atol=1e-5) for (x,y) in zip(a,b))

However, these non-allocating approaches do not seem to do exactly the same as OP, because for vector inputs a vector norm is used.

1 Like

Using isapprox elementwise is often a bad idea. For example:

julia> isapprox([1, 0], [1, 1e-16])
true

julia> all(isapprox.([1, 0], [1, 1e-16]))
false

1e-16 ≈ 0 is false, and rightly so, because the two numbers have no significant digits in common, and there is no reference by which to set an absolute scale. (You don’t know the “units”. See also the isapprox documentation on why the default tolerance is relative error, not absolute error.)

The advantage of applying isapprox to the whole array at once is that the norm of the whole array sets an overall scale with which to compare the elements: 1e-16 - 0 is small compared to the norm ≈ 1, so [1,0] ≈ [1,1e-16] rightly returns true.

Approximate comparison is one of those things that’s really easy to get wrong, unfortunately. (e.g. numpy.isclose got it wrong.)

PS. I think “non-allocating” here is probably an irrelevant metric. isapprox is not something that you usually do in performance-critical settings.

4 Likes