Skip to content

Commit

Permalink
Merge pull request #192 from kalmarek/fix-ambiguities
Browse files Browse the repository at this point in the history
Fix ambiguities
  • Loading branch information
Joel-Dahne authored Apr 25, 2024
2 parents 10b0f69 + 1edf991 commit 4f79faa
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 13 deletions.
4 changes: 4 additions & 0 deletions src/constructors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,22 @@ Mag(x) = set!(Mag(), x)
# later.
Mag(x::Union{MagRef,ArfRef}) = Mag(cstruct(x))
Mag(x, y) = set!(Mag(), x, y)
# disambiguation
Mag(x::Complex) = set!(Mag(), x)

# Arf
Arf(x; prec::Integer = _precision(x)) = set!(Arf(; prec), x)
# disambiguation
Arf(x::Arf; prec::Integer = precision(x)) = set!(Arf(; prec), x)
Arf(x::Rational; prec::Integer = _precision(x)) = set!(Arf(; prec), x)
Arf(x::Complex; prec::Integer = _precision(x)) = set!(Arf(; prec), x)

#Arb
Arb(x; prec::Integer = _precision(x)) = set!(Arb(; prec), x)
# disambiguation
Arb(x::Arb; prec::Integer = precision(x)) = set!(Arb(; prec), x)
Arb(x::Rational; prec::Integer = _precision(x)) = set!(Arb(; prec), x)
Arb(x::Complex; prec::Integer = _precision(x)) = set!(Arb(; prec), x)

function Arb(str::AbstractString; prec::Integer = DEFAULT_PRECISION[])
res = Arb(; prec)
Expand Down
23 changes: 14 additions & 9 deletions src/minmax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,18 @@ end
# doesn't solve the full problem.

# The default implementation in Base is not correct for Arb
Base._fast(::typeof(min), x::Arb, y::Arb) = min(x, y)
Base._fast(::typeof(min), x::Arb, y) = min(x, y)
Base._fast(::typeof(min), x, y::Arb) = min(x, y)
Base._fast(::typeof(max), x::Arb, y::Arb) = max(x, y)
Base._fast(::typeof(max), x::Arb, y) = max(x, y)
Base._fast(::typeof(max), x, y::Arb) = max(x, y)
Base._fast(::typeof(min), x::ArbOrRef, y::ArbOrRef) = min(x, y)
Base._fast(::typeof(min), x::ArbOrRef, y) = min(x, y)
Base._fast(::typeof(min), x, y::ArbOrRef) = min(x, y)
Base._fast(::typeof(max), x::ArbOrRef, y::ArbOrRef) = max(x, y)
Base._fast(::typeof(max), x::ArbOrRef, y) = max(x, y)
Base._fast(::typeof(max), x, y::ArbOrRef) = max(x, y)
# Handle ambiguous methods
Base._fast(::typeof(min), x::ArbOrRef, y::AbstractFloat) = min(x, y)
Base._fast(::typeof(min), x::AbstractFloat, y::ArbOrRef) = min(x, y)
Base._fast(::typeof(max), x::ArbOrRef, y::AbstractFloat) = max(x, y)
Base._fast(::typeof(max), x::AbstractFloat, y::ArbOrRef) = max(x, y)

# Mag, Arf and Arb don't have signed zeros
Base.isbadzero(::typeof(min), x::Union{Mag,Arf,Arb}) = false
Base.isbadzero(::typeof(max), x::Union{Mag,Arf,Arb}) = false
# Arf and Arb don't have signed zeros
Base.isbadzero(::typeof(min), x::Union{ArfOrRef,ArbOrRef}) = false
Base.isbadzero(::typeof(max), x::Union{ArfOrRef,ArbOrRef}) = false
12 changes: 12 additions & 0 deletions src/poly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,16 @@ function Base.:^(p::AcbSeries, q::AcbSeries)
deg = _degree(p, q)
return pow_series!(AcbSeries(degree = deg, prec = _precision(p, q)), p, q, deg + 1)
end
function Base.:^(p::ArbSeries, q::AcbSeries)
deg = _degree(p, q)
res = AcbSeries(p, degree = deg, prec = _precision(p, q))
return pow_series!(res, res, q, deg + 1)
end
function Base.:^(p::AcbSeries, q::ArbSeries)
deg = _degree(p, q)
res = AcbSeries(q, degree = deg, prec = _precision(p, q))
return pow_series!(res, p, res, deg + 1)
end

Base.:^(p::ArbSeries, e::Real) = pow_arb_series!(zero(p), p, convert(Arb, e), length(p))
function Base.:^(p::ArbSeries, e::Number)
Expand All @@ -678,6 +688,8 @@ Base.:^(p::ArbSeries, e::Integer) = pow_arb_series!(zero(p), p, convert(Arb, e),
Base.:^(p::AcbSeries, e::Integer) = pow_acb_series!(zero(p), p, convert(Acb, e), length(p))
Base.:^(p::ArbSeries, e::Rational) = pow_arb_series!(zero(p), p, convert(Arb, e), length(p))
Base.:^(p::AcbSeries, e::Rational) = pow_acb_series!(zero(p), p, convert(Acb, e), length(p))
Base.:^(::Irrational{:ℯ}, e::ArbSeries) = exp(e)
Base.:^(::Irrational{:ℯ}, e::AcbSeries) = exp(e)

##
## Series methods
Expand Down
10 changes: 10 additions & 0 deletions src/setters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ Base.setindex!(res::Union{MagLike,ArfLike,ArbLike,AcbLike}, x) = set!(res, x)
set!(res::MagLike, x::Integer) = set!(res, convert(UInt, x))
set!(res::MagLike, ::Irrational{:π}) = const_pi!(res)
set!(res::MagLike, x::Integer, y::Integer) = set_ui_2exp!(res, convert(UInt, x), y)
set!(res::MagLike, x::Complex) =
isreal(x) ? set!(res, real(x)) : throw(InexactError(:Mag, Mag, x))

# Arf
function set!(res::ArfLike, x::UInt128)
Expand Down Expand Up @@ -38,6 +40,9 @@ function set!(
return res
end

set!(res::ArfLike, x::Complex) =
isreal(x) ? set!(res, real(x)) : throw(InexactError(:Arf, Arf, x))

# Arb
function set!(res::ArbLike, x::Union{UInt128,Int128,MagLike,BigInt,BigFloat})
set!(midref(res), x)
Expand Down Expand Up @@ -98,6 +103,11 @@ function set!(res::ArbLike, (a, b)::Tuple{<:Real,<:Real}; prec::Integer = precis
return union!(res, a, b; prec)
end

set!(res::ArbLike, x::AcbOrRef) =
is_real(x) ? set!(res, realref(x)) : throw(InexactError(:Arb, Arb, x))
set!(res::ArbLike, x::Complex) =
isreal(x) ? set!(res, real(x)) : throw(InexactError(:Arb, Arb, x))

# Acb
function set!(res::AcbLike, x::Union{Real,MagLike,ArfLike,Tuple{<:Real,<:Real}})
set!(realref(res), x)
Expand Down
16 changes: 16 additions & 0 deletions test/constructors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
@test Mag(UInt64(1)) == Mag(1) == one(Mag) == one(Mag()) <= Mag(1.0)
@test π < Float64(Mag(π)) < 3.15
@test Mag(3, 4) == Mag(3 * 2^4)

# Check for ambiguities
@test Mag(1 + 0im) == Mag(1)
@test_throws InexactError Mag(1 + im)
end

@testset "Arf" begin
Expand All @@ -23,6 +27,10 @@

@test precision(zero(Arf(prec = 80))) == 80
@test precision(one(Arf(prec = 80))) == 80

# Check for ambiguities
@test Arf(1 + 0im) == 1
@test_throws InexactError Arf(1 + im)
end

@testset "Arb" begin
Expand Down Expand Up @@ -58,6 +66,10 @@
@test precision(Arb(MathConstants.catalan, prec = 80)) == 80
@test precision(Arb(MathConstants.φ, prec = 80)) == 80

@test Arb(Acb(1)) == 1
@test precision(Arb(Acb(1, prec = 80))) == 80
@test_throws InexactError Arb(Acb(1, 1))

# setball
@test isone(Arblib.setball(Arb, Arf(1), Mag(0)))
@test isone(Arblib.setball(Arb, 1, 0))
Expand All @@ -71,6 +83,10 @@

@test precision(Arblib.setball(Arb, Arf(prec = 80), 0)) == 80
@test precision(Arblib.setball(Arb, Arf(prec = 90), 0, prec = 80)) == 80

# Check for ambiguities
@test Arb(1 + 0im) == 1
@test_throws InexactError Arb(1 + im)
end

@testset "Acb" begin
Expand Down
34 changes: 32 additions & 2 deletions test/minmax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@
@test iszero(extrema(identity, -A)[2])

# Fails with default implementation due to Base._fast
#A = [Arb(0); [setball(Arb, 0, i) for i in reverse(0:257)]]
A = [setball(Arb, 0, i) for i = 0:257]
A = [Arb(0); [setball(Arb, 0, i) for i in reverse(0:257)]]
@test Arblib.contains(minimum(A), -257)
@test Arblib.contains(maximum(A), 257)
@test Arblib.contains(extrema(A)[1], -257)
Expand All @@ -71,6 +70,25 @@
@test Arblib.contains(maximum(identity, A), 257)
@test Arblib.contains(extrema(identity, A)[1], -257)
@test Arblib.contains(extrema(identity, A)[2], 257)
# In a previous version of Arblib, Base._fast was not correctly
# overloaded for ArbRef.
A = [
Arblib.realref(Acb(0))
[Arblib.realref(Acb(setball(Arb, 0, i))) for i in reverse(0:257)]
]
@test Arblib.contains(minimum(A), -257)
@test Arblib.contains(maximum(A), 257)
@test Arblib.contains(extrema(A)[1], -257)
@test Arblib.contains(extrema(A)[2], 257)
@test Arblib.contains(minimum(identity, A), -257)
@test Arblib.contains(maximum(identity, A), 257)
@test Arblib.contains(extrema(identity, A)[1], -257)
@test Arblib.contains(extrema(identity, A)[2], 257)
# In a previous version of Arblib, Base._fast was not correctly
# handling mixture of Arb and AbstractFloat
@test minimum(AbstractFloat[Arb(0); fill(1.0, 257)]) == 0
@test maximum(AbstractFloat[Arb(0); fill(1.0, 257)]) == 1
@test extrema(AbstractFloat[Arb(0); fill(1.0, 257)]) == (0, 1)

# Fails with default implementation due to both short circuit
# and Base._fast
Expand All @@ -92,17 +110,29 @@
@test !Base.isbadzero(min, zero(Mag))
@test !Base.isbadzero(min, zero(Arf))
@test !Base.isbadzero(min, zero(Arb))
@test !Base.isbadzero(min, Arblib.radref(zero(Arb)))
@test !Base.isbadzero(min, Arblib.midref(zero(Arb)))
@test !Base.isbadzero(min, Arblib.realref(zero(Acb)))

@test !Base.isbadzero(max, zero(Mag))
@test !Base.isbadzero(max, zero(Arf))
@test !Base.isbadzero(max, zero(Arb))
@test !Base.isbadzero(max, Arblib.radref(zero(Arb)))
@test !Base.isbadzero(max, Arblib.midref(zero(Arb)))
@test !Base.isbadzero(max, Arblib.realref(zero(Acb)))

@test !Base.isgoodzero(min, zero(Mag))
@test !Base.isgoodzero(min, zero(Arf))
@test !Base.isgoodzero(min, zero(Arb))
@test !Base.isgoodzero(min, Arblib.radref(zero(Arb)))
@test !Base.isgoodzero(min, Arblib.midref(zero(Arb)))
@test !Base.isgoodzero(min, Arblib.realref(zero(Acb)))

@test !Base.isgoodzero(max, zero(Mag))
@test !Base.isgoodzero(max, zero(Arf))
@test !Base.isgoodzero(max, zero(Arb))
@test !Base.isgoodzero(max, Arblib.radref(zero(Arb)))
@test !Base.isgoodzero(max, Arblib.midref(zero(Arb)))
@test !Base.isgoodzero(max, Arblib.realref(zero(Acb)))
end
end
18 changes: 17 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,23 @@ DocMeta.setdocmeta!(Arblib, :DocTestSetup, :(using Arblib); recursive = true)

@testset "Arblib" begin
doctest(Arblib)
Aqua.test_all(Arblib; ambiguities = (; broken = true))
# Some methods are excluded from the check for ambiguities. There
# are two reasons for these exclusions, methods in Base we don't
# care about and false positives from Aqua.

# The methods in Base that we don't care about are construction
# from AbstractChar or Base.TwicePrecision. Both of these have
# default constructors for Number types that clash with our catch
# all constructors. They do not seem important enough to warrant
# extra code for handling them.

# One set of false positives are for Arf(::Rational) and
# Arb(::Rational). The other set is for + and * with mix of
# ArbSeries and AcbSeries.
Aqua.test_all(
Arblib,
ambiguities = (exclude = [Mag, Arf, Arb, Acb, ArbSeries, AcbSeries, +, *],),
)

include("ArbCall/runtests.jl")

Expand Down
4 changes: 3 additions & 1 deletion test/series.jl
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@
p = TSeries([1, 2, 3])
q = TSeries([2, 3, 0])

@test p^q == TSeries([1, 4, 16])
@test p^q == ArbSeries([1, 2, 3])^q == p^ArbSeries([2, 3, 0]) == TSeries([1, 4, 16])

@test p^T(2) ==
p^Int(2) ==
Expand All @@ -322,6 +322,8 @@
@test 2^TSeries([1, 0]) == TSeries([2, 0])
@test (2 + im)^TSeries([1, 0]) == AcbSeries([2 + im, 0])

@test isequal(ℯ^p, exp(p))

@test precision(setprecision(p, 80)^setprecision(q, 90)) == 90
@test precision(setprecision(p, 80)^T(2)) == 80
end
Expand Down
14 changes: 14 additions & 0 deletions test/setters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

# Integer times power of 2
@test Arblib.set!(T(), 3, 4) == Arblib.set!(T(), 3 * 2^4)

# Complex
@test Arblib.set!(T(), 1 + 0im) == Mag(1)
@test_throws InexactError Arblib.set!(T(), 1 + 1im)
end

@testset "$name" for (name, T) in [("Arf", Arf), ("ArfRef", () -> Arblib.midref(Arb()))]
Expand Down Expand Up @@ -35,6 +39,10 @@
@test Arblib.set!(T(), 1 // BigInt(x)) == inv(Arf(x))
@test Arblib.set!(T(), BigInt(x) // (BigInt(x) + 1)) == Arf(x) / Arf(x + 1)
end

# Complex
@test Arblib.set!(T(), 1 + 0im) == 1
@test_throws InexactError Arblib.set!(T(), 1 + 1im)
end

@testset "$name" for (name, T) in
Expand Down Expand Up @@ -146,6 +154,12 @@
@test_throws ArgumentError Arblib.set!(T(), (2, 1))
@test_throws ArgumentError Arblib.set!(T(), (2.0, 1.0))
@test_throws ArgumentError Arblib.set!(T(), (2, 1.0))

# Complex
@test Arblib.set!(T(), Acb(1, 0)) == 1
@test_throws InexactError Arblib.set!(T(), Acb(1, 1))
@test Arblib.set!(T(), 1 + 0im) == 1
@test_throws InexactError Arblib.set!(T(), 1 + 1im)
end

@testset "$name" for (name, T) in [
Expand Down

0 comments on commit 4f79faa

Please sign in to comment.