Skip to content

Commit

Permalink
Merge branch 'master' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
kalmarek authored Apr 25, 2024
2 parents 26e753d + 1351b47 commit b71ca85
Show file tree
Hide file tree
Showing 14 changed files with 159 additions and 20 deletions.
6 changes: 4 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Arblib"
uuid = "fb37089c-8514-4489-9461-98f9c8763369"
authors = ["Marek Kaluba <kalmar@amu.edu.pl>", "Sascha Timme <Sascha Timme <timme@math.tu-berlin.de>", "Joel Dahne <joel@dahne.eu>"]
version = "1.2.0"
version = "1.2.1"

[deps]
FLINT_jll = "e134572f-a0d5-539d-bddf-3cad8db41a82"
Expand All @@ -11,6 +11,7 @@ Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"

[compat]
Aqua = "0.8"
Documenter = "1"
FLINT_jll = "~300.100.100"
LinearAlgebra = "1.6"
Expand All @@ -21,8 +22,9 @@ Test = "1.6"
julia = "1.6"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Documenter", "Test"]
test = ["Aqua", "Documenter", "Test"]
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.10081694.svg)](https://doi.org/10.5281/zenodo.10081694)
[![ci](https://github.com/kalmarek/Arblib.jl/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/kalmarek/Arblib.jl/actions/workflows/ci.yml?query=branch%3Amaster)
[![codecov](https://codecov.io/gh/kalmarek/Arblib.jl/graph/badge.svg?token=i1YYEc2Vht)](https://codecov.io/gh/kalmarek/Arblib.jl)
[![Aqua QA](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl)

This package is a thin, efficient wrapper around
[Arb](http://arblib.org) - a C library for arbitrary-precision ball
Expand Down
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
6 changes: 3 additions & 3 deletions src/multi-argument.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ for (jf, af) in [(:+, :add!), (:*, :mul!), (:min, :min!), (:max, :max!)]
end

for T in (ArfOrRef, ArbOrRef, AcbOrRef, ArbPoly, AcbPoly)
@eval @inline _precision(x::$T, y::$T, z::$T, rest::Vararg{S}) where {S<:$T} =
@eval @inline _precision(x::$T, y::$T, z::$T, rest::Vararg{$T}) =
max(precision(x), _precision(y, z, rest...))

for (jf, af) in [(:+, :add!), (:*, :mul!), (:min, :min!), (:max, :max!)]
Expand Down Expand Up @@ -68,9 +68,9 @@ for T in (ArfOrRef, ArbOrRef, AcbOrRef, ArbPoly, AcbPoly)
end

for T in (ArbSeries, AcbSeries)
@eval @inline _precision(x::$T, y::$T, z::$T, rest::Vararg{S}) where {S<:$T} =
@eval @inline _precision(x::$T, y::$T, z::$T, rest::Vararg{$T}) =
max(precision(x), _precision(y, z, rest...))
@eval @inline _degree(x::$T, y::$T, z::$T, rest::Vararg{S}) where {S<:$T} =
@eval @inline _degree(x::$T, y::$T, z::$T, rest::Vararg{$T}) =
min(degree(x), _degree(y, z, rest...))

for (jf, af) in [(:+, :add_series!), (:*, :mullow!)]
Expand Down
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
19 changes: 16 additions & 3 deletions src/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ function _remove_trailing_zeros(str::AbstractString)
# Numbers on the form xxx.yyy0ezzz
mantissa, exponent = split(str, 'e', limit = 2)
mantissa = rstrip(mantissa, '0')
if endswith(mantissa, '.')
if endswith(mantissa, '.') || endswith(mantissa, '}')
mantissa *= '0'
end
str = mantissa * 'e' * exponent
else
# Numbers on the form xxx.yyy0
str = rstrip(str, '0')
if endswith(str, '.')
if endswith(str, '.') || endswith(str, '}')
str *= '0'
end
end
Expand Down Expand Up @@ -129,7 +129,20 @@ end

function Base.show(io::IO, x::Union{ArbOrRef,AcbOrRef})
if Base.get(io, :compact, false) && rel_accuracy_bits(x) > 48
print(io, string(x, condense = 2, unicode = true))
str = string(x, condense = 2, unicode = true)
if isexact(x)
# For exact values the shortest output is in some cases
# not given by condensing the decimal digits, but by
# removing trailing zeros. We try both options and take
# the shortest.

str_alt = string(x)

if length(str_alt) < length(str)
str = str_alt
end
end
print(io, str)
else
print(io, string(x))
end
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
19 changes: 19 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,29 @@ ENV["NEMO_THREADED"] = 1
using Arblib, Test, LinearAlgebra, Random, Serialization, SpecialFunctions
using Documenter

import Aqua

DocMeta.setdocmeta!(Arblib, :DocTestSetup, :(using Arblib); recursive = true)

@testset "Arblib" begin
doctest(Arblib)
# 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
Loading

0 comments on commit b71ca85

Please sign in to comment.