Isapprox documentation has argument norm, but call signature does not?

I noticed this trying to extend the function. I am using:

 Julia Version 1.3.0-rc4.1
Commit 8c4656b97a (2019-10-15 14:08 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin18.6.0)
  CPU: Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, skylake)
Environment:
  JULIA_NUM_THREADS = 4

first post, so be kind :wink:

1 Like
julia> methods(isapprox)
# 9 methods for generic function "isapprox":
[1] isapprox(::Missing, ::Missing; kwargs...) in Base at missing.jl:89
[2] isapprox(::Missing, ::Any; kwargs...) in Base at missing.jl:90
[3] isapprox(::Any, ::Missing; kwargs...) in Base at missing.jl:91
[4] isapprox(x::Number, y::Number; atol, rtol, nans) in Base at floatfuncs.jl:274
[5] isapprox(x::AbstractArray, y::AbstractArray; atol, rtol, nans, norm) in LinearAlgebra at C:\cygwin\home\Administrator\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.3\LinearAlgebra\src\generic.jl:1522
[6] isapprox(J1::LinearAlgebra.UniformScaling{T}, J2::LinearAlgebra.UniformScaling{S}; atol, rtol, nans) where {T<:Number, S<:Number} in LinearAlgebra at C:\cygwin\home\Administrator\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.3\LinearAlgebra\src\uniformscaling.jl:253
[7] isapprox(J::LinearAlgebra.UniformScaling, A::AbstractArray{T,2} where T; atol, rtol, nans, norm) in LinearAlgebra at C:\cygwin\home\Administrator\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.3\LinearAlgebra\src\uniformscaling.jl:259
[8] isapprox(A::AbstractArray{T,2} where T, J::LinearAlgebra.UniformScaling; kwargs...) in LinearAlgebra at C:\cygwin\home\Administrator\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.3\LinearAlgebra\src\uniformscaling.jl:265
[9] isapprox(c1::D, c2::D) where D<:DiscreteNonParametric in Distributions at C:\Users\andre\.julia\packages\Distributions\wRw5p\src\univariate\discrete\discretenonparametric.jl:66

hi!, maybe it’s because is a keyword argument? and keywords don’t participate in dispatch. but it works anyway. for example:

x = rand(5)
y = rand(5)
mynorm(x) = length(x) - 5 #not a real norm, but if the length of (y-x) is 5, then they are equal
isapprox(x,y,norm=mynorm) #returns true
2 Likes

Thanks.

There is no norm option if the entries are Numbers. I have a composite data type that contained a Number and several Arrays. I need to pass the “norm” option on when computing the Array parts and not when computing the scalar part. This is clear from method list item [4] in the isapprox methods.

x = rand(1)
y = rand(1)
mynorm(x) = length(x) - 5 #not a real norm, but if the length of (y-x) is 5, then they are equal
isapprox(x,y,norm=mynorm)

Works

But

mynorm(x) = length(x) - 5 #a real norm, but if the length of (y-x) is 5, then they are equal
isapprox(1, 1,norm=mynorm)

Yields

ERROR: MethodError: no method matching isapprox(::Int64, ::Int64; norm=mynorm)
Closest candidates are:
  isapprox(::Number, ::Number; atol, rtol, nans) at floatfuncs.jl:274 got unsupported keyword argument "norm"

The Array parts fall into methods list item [5] and so they can use it.

I can actually see a use for the norm on Numbers, but it’s sufficiently weird that it is not a worry at least for now.

Rookie error. Your post helped me see it. Thanks!

I think that the docstring of isapprox is a bit misleading, since not all methods support all keyword arguments. Perhaps it should be broken up into relevant parts for each method.

That said, I think that specifying a custom norm, especially in tests, is often more convoluted than just calculating the discrepancy I care about directly.

1 Like

Alternatively, the call signatures could be made more uniform. The norm option isn’t terribly useful for scalars, but why not support it?

4 Likes

I noticed it because I wanted to use it.

Contrived:
Where scalars are part of a larger structure, think unit quaternions, with a scalar part and a vector part. In such a case the scalar norm might be part of a larger computation, and the most convenient thing might be a different scalar norm.

If I’m trying to optimize an attitude maneuver (a rotation), I want a partial order (semi-norm), on the size of the angle. The scalar part of a unit quaternion is \cos \frac{\theta}{2}, when the unit quaternion is representing a rotation. So I would want to take the \arccos and compare \theta’s not \cos \frac{\theta}{2}’s.

N.B. There are better ways to do this - I indicated it’s contrived.

Of course, scalar norm in the usual case should be blazingly fast. But that’s why Julia is compiled.

I hope this helps.

1 Like