Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ambiguities #192

Merged
merged 6 commits into from
Apr 25, 2024
Merged

Fix ambiguities #192

merged 6 commits into from
Apr 25, 2024

Conversation

Joel-Dahne
Copy link
Collaborator

The goal of this PR is to fix all the ambiguities reported by Aqua, see #186. It is not fully finished, there are still some ambiguities left to handle, hence the tests currently fails.

The remaining ones to handle are:

  • (::Type{T})(z::Complex) where T<:Real (3 ambiguities)
  • (::Type{T})(x::Rational{S}) where {S, T<:AbstractFloat} (2 ambiguities)
    • and * for ArbSeries and AcbSeries (2 ambiguities)

For the ones related to Complex it should be straight forward to add, I just didn't have the time to finish it yet. I will probably add similar methods for Acb in that case as well.

For the other ones I have, as mentioned in #186, not been able to trigger them. The reported issues are

Ambiguity #1
*(p::Union{Arblib.AcbPoly, Arblib.AcbSeries}, c::Number) @ Arblib ~/Syncthing/Work/Code/Arblib.jl/src/poly.jl:481
*(c::Number, p::Union{Arblib.AcbPoly, Arblib.AcbSeries, Arblib.ArbPoly, Arblib.ArbSeries}) @ Arblib ~/Syncthing/Work/Code/Arblib.jl/src/poly.jl:533

Possible fix, define
  *(::Arblib.AcbSeries, ::Union{Arblib.AcbSeries, Arblib.ArbSeries})

Ambiguity #2
+(p::Union{Arblib.AcbPoly, Arblib.AcbSeries}, c::Number) @ Arblib ~/Syncthing/Work/Code/Arblib.jl/src/poly.jl:455
+(c::Number, p::Union{Arblib.AcbPoly, Arblib.AcbSeries, Arblib.ArbPoly, Arblib.ArbSeries}) @ Arblib ~/Syncthing/Work/Code/Arblib.jl/src/poly.jl:532

Possible fix, define
  +(::Arblib.AcbSeries, ::Union{Arblib.AcbSeries, Arblib.ArbSeries})

Ambiguity #3
Arblib.Arb(x; prec) @ Arblib ~/Syncthing/Work/Code/Arblib.jl/src/constructors.jl:22
(::Type{T})(x::Rational{S}) where {S, T<:AbstractFloat} @ Base rational.jl:133

Possible fix, define
  Arblib.Arb(::Rational{S}) where S

Ambiguity #5
Arblib.Arf(x; prec) @ Arblib ~/Syncthing/Work/Code/Arblib.jl/src/constructors.jl:14
(::Type{T})(x::Rational{S}) where {S, T<:AbstractFloat} @ Base rational.jl:133

Possible fix, define
  Arblib.Arf(::Rational{S}) where S

But everything seems to work fine

#1
AcbSeries() * AcbSeries()
AcbSeries() * ArbSeries()

#2
AcbSeries() + AcbSeries()
AcbSeries() + ArbSeries()

#3
Arb(1 // 2)
Arb(Rational{Int32}(1, 2))

#4
Arf(1 // 2)
Arf(Rational{Int32}(1, 2))

Am I missing something here?

@Joel-Dahne
Copy link
Collaborator Author

Now I have updated it so that all ambiguities other than the ones I think are false positives are fixed. Towards the end I however realized that there might be a better way to handle the constructors, more about the alternative solution below.

False positives

It currently reports the following issues

4 ambiguities found. To get a list, set `broken = false`.
Ambiguity #1
*(p::Union{Arblib.AcbPoly, Arblib.AcbSeries}, c::Number) @ Arblib ~/Syncthing/Work/Code/Arblib.jl/src/poly.jl:485
*(c::Number, p::Union{Arblib.AcbPoly, Arblib.AcbSeries, Arblib.ArbPoly, Arblib.ArbSeries}) @ Arblib ~/Syncthing/Work/Code/Arblib.jl/src/poly.jl:537

Possible fix, define
  *(::Arblib.AcbSeries, ::Union{Arblib.AcbSeries, Arblib.ArbSeries})

Ambiguity #2
+(p::Union{Arblib.AcbPoly, Arblib.AcbSeries}, c::Number) @ Arblib ~/Syncthing/Work/Code/Arblib.jl/src/poly.jl:459
+(c::Number, p::Union{Arblib.AcbPoly, Arblib.AcbSeries, Arblib.ArbPoly, Arblib.ArbSeries}) @ Arblib ~/Syncthing/Work/Code/Arblib.jl/src/poly.jl:536

Possible fix, define
  +(::Arblib.AcbSeries, ::Union{Arblib.AcbSeries, Arblib.ArbSeries})

Ambiguity #3
Arblib.Arb(x::Union{Ptr{Arblib.arb_struct}, Ptr{Arblib.arf_struct}, Ptr{Arblib.mag_struct}, Arblib.arb_struct, Arblib.arf_struct, Arblib.mag_struct, Real, Tuple{Union{Ptr{Arblib.arf_struct}, Ptr{Arblib.mag_struct}, Arblib.Arf, Arblib.ArfRef, Arblib.Mag, Arblib.MagRef, Arblib.arf_struct, Arblib.mag_struct, BigFloat}, Union{Ptr{Arblib.arf_struct}, Ptr{Arblib.mag_struct}, Arblib.Arf, Arblib.ArfRef, Arblib.Mag, Arblib.MagRef, Arblib.arf_struct, Arblib.mag_struct, BigFloat}}, Tuple{Real, Real}}; prec) @ Arblib ~/Syncthing/Work/Code/Arblib.jl/src/constructors.jl:24
(::Type{T})(x::Rational{S}) where {S, T<:AbstractFloat} @ Base rational.jl:133

Possible fix, define
  Arblib.Arb(::Rational{S}) where S

Ambiguity #4
Arblib.Arf(x::Union{Ptr{Arblib.arf_struct}, Ptr{Arblib.mag_struct}, Arblib.arf_struct, Arblib.mag_struct, Real}; prec) @ Arblib ~/Syncthing/Work/Code/Arblib.jl/src/constructors.jl:15
(::Type{T})(x::Rational{S}) where {S, T<:AbstractFloat} @ Base rational.jl:133

Possible fix, define
  Arblib.Arf(::Rational{S}) where S

As mentioned above I'm however not able to trigger any of these. In fact all of them have specific definitions already, but they seem to not get picked up by Aqua.

We already have the methods

Arf(x::Rational; prec::Integer = _precision(x)) = set!(Arf(; prec), x)
Arb(x::Rational; prec::Integer = _precision(x)) = set!(Arb(; prec), x)

The warning related to those go away if they are instead defined as

Arf(x::Rational{S}; prec::Integer = _precision(x)) where {S} = set!(Arf(; prec), x)
Arb(x::Rational{S}; prec::Integer = _precision(x)) where {S} = set!(Arb(; prec), x)

But as fair as I know these are equivalent?

Similarly we already have methods for the + and * for series. Again it is however not in exactly the form Aqua proposes. The current relevant definitions are

for T in [ArbSeries, AcbSeries]
    @eval function Base.:+(p::$T, q::$T)
        deg = _degree(p, q)
        return add_series!($T(degree = deg, prec = _precision(p, q)), p, q, deg + 1)
    end
    @eval function Base.:*(p::$T, q::$T)
        deg = _degree(p, q)
        return mullow!($T(degree = deg, prec = _precision(p, q)), p, q, deg + 1)
    end
end

function Base.:+(p::AcbSeries, q::ArbSeries)
    deg = _degree(p, q)
    res = AcbSeries(q, degree = deg, prec = _precision(p, q))
    return add_series!(res, p, res, deg + 1)
end

function Base.:*(p::AcbSeries, q::ArbSeries)
    deg = _degree(p, q)
    res = AcbSeries(q, degree = deg, prec = _precision(p, q))
    return mullow!(res, p, res, deg + 1)
end

Which should cover all cases. But Aqua doesn't seem to pick it up. Am I just missing something here or is this a problem with Aqua? I looked for any open issues on Aqua related to false positives, but couldn't find anything. Do you know anything about this @devmotion?

Alternative solution

Let me take Arb as an example in the following, though the same holds true with minor changes for Mag, Arf and Acb as well.

The need to define separate constructors for Arb from Complex, AbstractChar and Base.TwicePrecision are due to our "catch-all" constructor

Arb(x; prec::Integer = _precision(x)) = set!(Arb(; prec), x)

It cant know if this constructor should be used or the default one for e.g. AbstractChar. Instead of explicitly constructors from Complex, AbstractChar and Base.TwicePrecision, one option would be to limit the type in our current constructor. To catch all cases we currently support one would however get a slightly involved argument type, more precisely the following seems to be enough

Arb(
    x::Union{Real,Tuple{<:Real,<:Real},NTuple{2,Union{MagLike,ArfLike,BigFloat}},MagLike,ArfLike,ArbLike};
    prec::Integer = _precision(x),
) = set!(Arb(; prec), x)

At least it passes all the tests. One benefit with specializing our constructor like this is that we don't have to write the code for construction from Complex, AbstractChar and Base.TwicePrecision, we can instead use the default implementations (which work well). Which means less code for us to maintain.

Do you have any preferences between the two alternatives @kalmarek? I'm currently leaning towards the latter one, i.e. adding the above type constraint to the Arb constructor. The main reason being that we are then not responsible for more code than necessary. I could see both options being valid though.

@kalmarek
Copy link
Owner

@Joel-Dahne Congratulations on handing in the thesis! and thanks for picking this up so quickly!

Honestly speaking I don't like the idea of changing our code style just to satisfy some tool ;) Looking at Aqua docs I see that it is possible to override the reported ambiguities for specific methods like this:
https://juliatesting.github.io/Aqua.jl/stable/#...to-your-tests?

ambiguities=(exclude=[Arblib.Arb], broken=true),

what do you think about this?

@Joel-Dahne
Copy link
Collaborator Author

I agree, it is a lot of code to handle some edge cases that most likely no one will care about. I'll try that override and remove changes to the constructors I have made. I'll probably keep the constructor from Complex though, I was not aware of it and I could see it being useful as a shorthand for e.g. @assert isreal(x); return real(x).

Fixes two issues with the implementation of `Base._fast` and one issue
with the tests.

- It no longer has ambiguities for `Base._fast(::typeof(min), x::Arb,
  y::AbstractFloat)`.
- It now also supports `ArbRef`, the previous version would give
  wrong results.
- Fix the test for `Base._fast` not actually using an input for which
  it would otherwise fail.

Also added tests for all changes.
It is no longer defined for `Mag`, since `Mag` is not an
`AbstractFloat` it is not needed. It is now defined for `ArfRef` and
`ArbRef`.
Similar to the methods in Base they throw an error for non-real input.
For Mag, Arf and Arb they are defined for Complex and for Arb also for
Acb.
@Joel-Dahne
Copy link
Collaborator Author

Okay, here is a new version! It fixes the problematic ambiguities and adds a setter from Complex. It ignores a number of method ambiguities in the tests and I have added a detailed comment about why what we ignore and why.

The false positives from Aqua we should however maybe report? As far as I can tell they are bugs? If they are fixed we can remove the ignore for + and *.

@Joel-Dahne Joel-Dahne merged commit 4f79faa into master Apr 25, 2024
11 checks passed
@Joel-Dahne Joel-Dahne deleted the fix-ambiguities branch April 25, 2024 11:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants