Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
54a066c
fix: Cap the decoration of the two-argument atan at dac on its branch…
OlivierHnt Aug 24, 2026
5d29b56
fix: Define acot at 0 and decorate its jump like the two-argument atan
OlivierHnt Aug 24, 2026
5eadd00
fix: Fall back to :correct rounding when CoreMath has no routine
OlivierHnt Aug 24, 2026
80488eb
fix: Rework Piecewise internals
OlivierHnt Aug 24, 2026
e94c6d3
test: Rework the test suite
OlivierHnt Aug 24, 2026
72b389f
test: Remove fragile @allocated assertions
OlivierHnt Aug 24, 2026
72146ce
fix: Support small Rational bound types in sample
OlivierHnt Aug 24, 2026
2d8daff
test: Fix CI failures across platforms
OlivierHnt Aug 24, 2026
f220abb
test: Remove the remaining platform-dependent Float16 CoreMath pins
OlivierHnt Aug 24, 2026
fc30cd6
test: Make type assertions independent of the word size
OlivierHnt Aug 24, 2026
8b4d2e5
test: Fix the remaining word-size and architecture dependent assertions
OlivierHnt Aug 24, 2026
1604cd6
test: Gate CoreMath tests on library availability and qualify Forward…
OlivierHnt Aug 24, 2026
5a27b7b
fix: Disambiguate mul! from the structured matrix methods of LinearAl…
OlivierHnt Aug 24, 2026
e78b289
fix: Print interval bounds as Julia Base within the significant digits
OlivierHnt Aug 24, 2026
50501eb
test: Update complex display expectations to the Base-consistent output
OlivierHnt Aug 24, 2026
5f34b17
fix: Restrict sample to float bound types
OlivierHnt Aug 27, 2026
c2369e9
test: Remove the ITF1788 reduction tests
OlivierHnt Aug 27, 2026
dd3bdcb
test: Discover the repository tests via a directory walk
OlivierHnt Aug 27, 2026
4abbd4b
fix: Address the review comments for Piecewise
OlivierHnt Aug 27, 2026
eab4cc5
fix: Define the mul! disambiguation methods only on Julia v1.10
OlivierHnt Aug 27, 2026
c7e3f8a
test: Remove the reduction operations from the ITL files
OlivierHnt Aug 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions ext/IntervalArithmeticLinearAlgebraExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,22 @@ function LinearAlgebra.mul!(C::AbstractMatrix{<:RealOrComplexI}, A::AbstractVecO
return _mul!(IntervalArithmetic.default_matmul(), C, A, B, α, β)
end

# disambiguate from the LinearAlgebra methods for structured matrices of Julia v1.10
if VERSION < v"1.11"
const _StructuredMatrix = Union{LinearAlgebra.Bidiagonal,LinearAlgebra.Diagonal,LinearAlgebra.SymTridiagonal,LinearAlgebra.Tridiagonal}

for (CT, AT, BT) ∈ (
(:(AbstractMatrix{<:RealOrComplexI}), :AbstractMatrix, :_StructuredMatrix),
(:(AbstractMatrix{<:RealOrComplexI}), :_StructuredMatrix, :AbstractMatrix),
(:(AbstractMatrix{<:RealOrComplexI}), :_StructuredMatrix, :_StructuredMatrix),
(:(AbstractVector{<:RealOrComplexI}), :_StructuredMatrix, :AbstractVector))
@eval function LinearAlgebra.mul!(C::$CT, A::$AT, B::$BT, α::Number, β::Number)
size(A, 2) == size(B, 1) || return throw(DimensionMismatch("The number of columns of A must match the number of rows of B."))
return _mul!(IntervalArithmetic.default_matmul(), C, A, B, α, β)
end
end
end

#

LinearAlgebra.mul!(C::AbstractVecOrMat{<:RealOrComplexI}, A::AbstractMatrix{<:RealOrComplexI}, B::AbstractVecOrMat{<:RealOrComplexI}) =
Expand Down
7 changes: 2 additions & 5 deletions src/IntervalArithmetic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,9 @@ Random.rand(rng::Random.AbstractRNG, ::Random.SamplerType{Interval{T}}) where {T

sample(x::Interval) = sample(Random.default_rng(), x)

function sample(rng::Random.AbstractRNG, x::Interval{T}) where {T<:NumTypes}
function sample(rng::Random.AbstractRNG, x::Interval{T}) where {T<:AbstractFloat}
lo, hi = bounds(x)
β = rand(rng, float(T))
β = rand(rng, T)
lo = ifelse(lo == typemin(T), _value_min(T), lo)
hi = ifelse(hi == typemax(T), _value_max(T), hi)
val = convert(T, (1 - β) * lo + β * hi)
Expand All @@ -281,9 +281,6 @@ end
_value_min(::Type{T}) where {T<:AbstractFloat} = floatmin(T)
_value_max(::Type{T}) where {T<:AbstractFloat} = floatmax(T)

_value_min(::Type{Rational{T}}) where {T<:Integer} = convert(Rational{T}, typemin(T))
_value_max(::Type{Rational{T}}) where {T<:Integer} = convert(Rational{T}, typemax(T))

export sample

#
Expand Down
7 changes: 5 additions & 2 deletions src/display.jl
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,11 @@ function _round_string(x::AbstractFloat, sigdigits::Int)
return str
end

_round_string(x::AbstractFloat, sigdigits::Int, mode::RoundingMode) =
_round_string(round(x, mode; sigdigits = sigdigits), sigdigits)
# print as Julia Base whenever the shortest representation fits within `sigdigits`
function _round_string(x::AbstractFloat, sigdigits::Int, mode::RoundingMode)
_count_sigdigits(string(x)) ≤ sigdigits && return _round_string(x, sigdigits)
return _round_string(round(x, mode; sigdigits = sigdigits), sigdigits)
end

_count_sigdigits(s::AbstractString) = length(replace(split(s, r"[eE]")[1], '-' => "", '.' => "", r"^0+" => ""))

Expand Down
20 changes: 14 additions & 6 deletions src/intervals/arithmetic/trigonometric.jl
Original file line number Diff line number Diff line change
Expand Up @@ -501,26 +501,34 @@ Base.atan(x::Complex{Interval{T}}) where {T<:NumTypes} =
acot(::BareInterval)
acot(::Interval)

This function is not part of the IEEE Standard 1788-2015.
This function is not part of the IEEE Standard 1788-2015. It uses the convention
`acot(0) = π/2` and the jump at 0 is decorated like the branch cut of the
two-argument `atan` described as `atan2` in the IEEE Standard 1788-2015
(Table 9.1).
"""
function Base.acot(x::BareInterval{T}) where {T<:AbstractFloat}
isempty_interval(x) && return x
lo, hi = bounds(x)
if lo < 0 < hi || lo == hi == 0
if lo < 0 && hi 0
HALF_PI_HI = sup(_half_pi(T))
return _unsafe_bareinterval(T, -HALF_PI_HI, HALF_PI_HI)
elseif lo == 0
hi == 0 && return _half_pi(T)
return @round(T, acot(hi), +sup(_half_pi(T)))
elseif hi == 0
return @round(T, -sup(_half_pi(T)), acot(lo))
else
return @round(T, acot(hi), acot(lo))
end
end

Base.acot(x::BareInterval{<:Rational}) = acot(float(x))

# automatically defined for `Interval` since it is a subtype of `Real`
function Base.acot(x::Interval)
bx = bareinterval(x)
r = acot(bx)
d = min(decoration(x), decoration(r))
d = min(d, ifelse(in_interval(0, bx), ifelse(inf(bx) < 0, def, dac), d))
return _unsafe_interval(r, d, isguaranteed(x))
end

"""
atan(::BareInterval, ::BareInterval)
Expand Down Expand Up @@ -588,7 +596,7 @@ function Base.atan(y::Interval, x::Interval)
ifelse(in_interval(0, by),
ifelse(in_interval(0, bx),
trv,
ifelse(sup(bx) < 0, ifelse(inf(by) < 0, def, d), d)),
ifelse(sup(bx) < 0, ifelse(inf(by) < 0, def, dac), d)),
d))
t = isguaranteed(y) & isguaranteed(x)
return _unsafe_interval(r, d, t)
Expand Down
10 changes: 7 additions & 3 deletions src/intervals/rounding.jl
Original file line number Diff line number Diff line change
Expand Up @@ -138,15 +138,19 @@ for f ∈ (:cbrt, :exp, :exp2, :exp10, :expm1, # exponential
end
end

# if CRlibm has no routine, dispatch falls back to the shared `:correct` methods above
if f ∈ CRlibm.functions
@eval _fround(::typeof($f), ::IntervalRounding{:correct}, x::Float16, r::RoundingMode) = Float16(_fround($f, Float64(x), r), r)
@eval _fround(::typeof($f), ::IntervalRounding{:correct}, x::Union{Float32,Float64}, r::RoundingMode) = CRlibm.$f(x, r)
end

@eval _fround(::typeof($f), ::IntervalRounding{:ulp}, x::Union{Float16,Float32,Float64}, ::RoundingMode{:Down}) = prevfloat(CoreMath.$coremath_f(x))
@eval _fround(::typeof($f), ::IntervalRounding{:ulp}, x::Union{Float16,Float32,Float64}, ::RoundingMode{:Up}) = nextfloat(CoreMath.$coremath_f(x))
# if CoreMath has no routine, dispatch falls back to the shared `:correct` methods above
if f ∈ CoreMath.univariate_functions
@eval _fround(::typeof($f), ::IntervalRounding{:ulp}, x::Union{Float16,Float32,Float64}, ::RoundingMode{:Down}) = prevfloat(CoreMath.$coremath_f(x))
@eval _fround(::typeof($f), ::IntervalRounding{:ulp}, x::Union{Float16,Float32,Float64}, ::RoundingMode{:Up}) = nextfloat(CoreMath.$coremath_f(x))
end

@eval _fround(::typeof($f), ::IntervalRounding{:none}, x::AbstractFloat, r::RoundingMode) = $f(x)
@eval _fround(::typeof($f), ::IntervalRounding{:none}, x::AbstractFloat, ::RoundingMode) = $f(x)
end

# 2-argument functions
Expand Down
Loading
Loading