Skip to content

Commit 3b1aff6

Browse files
committed
Extend configure for flavour, power mode, matmul mode and default numtype
1 parent b532a27 commit 3b1aff6

File tree

11 files changed

+168
-105
lines changed

11 files changed

+168
-105
lines changed

src/IntervalArithmetic.jl

Lines changed: 139 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,57 @@
11
"""
22
IntervalArithmetic
33
4-
Library for validated numerics using interval arithmetic.
4+
Library for validated numerics using interval arithmetic, offering tools to
5+
rigorously bound errors in numerical computations by representing values as
6+
intervals and ensuring that computed results contain the true value. It provides
7+
accurate, and efficient methods, ideal for scientific computing,
8+
computer-assisted proofs, and any domain requiring certified numerical results.
9+
10+
Key features:
11+
12+
- **Bound Type**: The default numerical type used to represent the bounds of the
13+
intervals. The default is `Float64`, but other subtypes of
14+
[`IntervalArithmetic.NumTypes`](@ref) can be used to adjust precision.
15+
16+
- **Flavor**: The interval representation that adhere to the IEEE Standard
17+
1788-2015. By default, it uses the set-based flavor, which excludes infinity
18+
to be part of an interval. Learn more: [`IntervalArithmetic.Flavor`](@ref).
19+
20+
- **Interval Rounding**: Controls the rounding behavior for interval arithmetic
21+
operations. By default, the library employs correct rounding to ensure that
22+
bounds are computed as tightly as possible. Learn more:
23+
[`IntervalArithmetic.IntervalRounding`](@ref).
24+
25+
- **Power mode**: A performance setting for power operations. The default mode
26+
uses an efficient algorithm prioritizing fast computation, but it can be
27+
adjusted for more precise, slower calculations if needed. Learn more:
28+
[`IntervalArithmetic.PowerMode`](@ref).
29+
30+
- **Matrix Multiplication mode**: A performance setting for matrix
31+
multiplication operations. The default mode uses an efficient algorithm
32+
prioritizing fast computation, but it can be changed to use the standard
33+
definition of matrix multiplication. Learn more:
34+
[`IntervalArithmetic.MatMulMode`](@ref).
35+
36+
The default behaviors described above can be configured via
37+
[`IntervalArithmetic.configure`](@ref).
38+
39+
**Display Settings**: controls how intervals are displayed. By default,
40+
intervals are shown using the standard mathematical notation ``[a, b]``, along
41+
with decorations and up to 6 significant digits. Learn more:
42+
[`setdisplay`](@ref).
43+
44+
# Usage
45+
46+
```julia
47+
using IntervalArithmetic
48+
49+
# Create an interval
50+
x = interval(1.0, 2.0)
51+
52+
# Perform a rigorous computation
53+
x + exp(interval(π))
54+
```
555
656
Learn more: https://github.com/JuliaIntervals/IntervalArithmetic.jl
757
"""
@@ -32,10 +82,6 @@ include("display.jl")
3282

3383
#
3484

35-
include("symbols.jl")
36-
37-
#
38-
3985
import LinearAlgebra
4086
import OpenBLASConsistentFPCSR_jll # 32-bit systems are not supported
4187

@@ -50,6 +96,27 @@ include("matmul.jl")
5096

5197
#
5298

99+
function configure_numtype(numtype::Type{<:NumTypes})
100+
@eval promote_numtype(::Type{T}, ::Type{S}) where {T,S} = promote_type($numtype, numtype(T), numtype(S))
101+
@eval macro interval(expr)
102+
return _wrap_interval($numtype, expr)
103+
end
104+
@eval _parse(str::AbstractString) = parse(Interval{$numtype}, str)
105+
@eval emptyinterval() = emptyinterval(Interval{$numtype})
106+
@eval entireinterval() = entireinterval(Interval{$numtype})
107+
@eval nai() = nai(Interval{$numtype})
108+
return numtype
109+
end
110+
111+
function configure_flavor(flavor::Symbol)
112+
flavor == :set_based || return throw(ArgumentError("only the interval flavor `:set_based` is supported and implemented"))
113+
@eval zero_times_infinity(::Type{T}) where {T<:NumTypes} = zero_times_infinity(Flavor{$(QuoteNode(flavor))}(), T)
114+
@eval div_by_thin_zero(x::BareInterval) = div_by_thin_zero(Flavor{$(QuoteNode(flavor))}(), x)
115+
@eval contains_infinity(x::BareInterval) = contains_infinity(Flavor{$(QuoteNode(flavor))}(), x)
116+
@eval is_valid_interval(a::Real, b::Real) = is_valid_interval(Flavor{$(QuoteNode(flavor))}(), a, b)
117+
return flavor
118+
end
119+
53120
function configure_rounding(rounding::Symbol)
54121
rounding (:correct, :none) || return throw(ArgumentError("only the rounding mode `:correct` and `:none` are available"))
55122

@@ -86,15 +153,80 @@ function configure_rounding(rounding::Symbol)
86153
return rounding
87154
end
88155

89-
function configure(; rounding::Symbol=:correct)
156+
function configure_power(power::Symbol)
157+
power (:slow, :fast) || return throw(ArgumentError("only the power mode `:slow` and `:fast` are available"))
158+
159+
for f (:_select_pow, :_select_pown)
160+
@eval $f(x, y) = $f(PowerMode{$(QuoteNode(power))}(), x, y)
161+
end
162+
163+
return power
164+
end
165+
166+
function configure_matmul(matmul::Symbol)
167+
matmul (:slow, :fast) || return throw(ArgumentError("only the matrix multiplication mode `:slow` and `:fast` are available"))
168+
169+
@eval begin
170+
function LinearAlgebra.mul!(C::AbstractVector{<:RealOrComplexI}, A::AbstractVecOrMat, B::AbstractVector, α::Number, β::Number)
171+
size(A, 2) == size(B, 1) || return throw(DimensionMismatch("The number of columns of A must match the number of rows of B."))
172+
return _mul!(MatMulMode{$(QuoteNode(matmul))}(), C, A, B, α, β)
173+
end
174+
175+
function LinearAlgebra.mul!(C::AbstractMatrix{<:RealOrComplexI}, A::AbstractVecOrMat, B::AbstractVecOrMat, α::Number, β::Number)
176+
size(A, 2) == size(B, 1) || return throw(DimensionMismatch("The number of columns of A must match the number of rows of B."))
177+
return _mul!(MatMulMode{$(QuoteNode(matmul))}(), C, A, B, α, β)
178+
end
179+
end
180+
181+
return matmul
182+
end
183+
184+
"""
185+
configure(; numtype=Float64, flavor=:set_based, rounding=:correct, power=:fast, matmul=:fast)
186+
187+
Configure the default behavior for:
188+
189+
- **Bound Type**: The default numerical type used to represent the bounds of the
190+
intervals. The default is `Float64`, but other subtypes of
191+
[`IntervalArithmetic.NumTypes`](@ref) can be used to adjust precision.
192+
193+
- **Flavor**: The interval representation that adhere to the IEEE Standard
194+
1788-2015. By default, it uses the set-based flavor, which excludes infinity
195+
to be part of an interval. Learn more: [`IntervalArithmetic.Flavor`](@ref).
196+
197+
- **Interval Rounding**: Controls the rounding behavior for interval arithmetic
198+
operations. By default, the library employs correct rounding to ensure that
199+
bounds are computed as tightly as possible. Learn more:
200+
[`IntervalArithmetic.IntervalRounding`](@ref).
201+
202+
- **Power mode**: A performance setting for power operations. The default mode
203+
uses an efficient algorithm prioritizing fast computation, but it can be
204+
adjusted for more precise, slower calculations if needed. Learn more:
205+
[`IntervalArithmetic.PowerMode`](@ref).
206+
207+
- **Matrix Multiplication mode**: A performance setting for matrix
208+
multiplication operations. The default mode uses an efficient algorithm
209+
prioritizing fast computation, but it can be changed to use the standard
210+
definition of matrix multiplication. Learn more:
211+
[`IntervalArithmetic.MatMulMode`](@ref).
212+
"""
213+
function configure(; numtype::Type{<:NumTypes}=Float64, flavor::Symbol=:set_based, rounding::Symbol=:correct, power::Symbol=:fast, matmul::Symbol=:fast)
214+
configure_numtype(numtype)
215+
configure_flavor(flavor)
90216
configure_rounding(rounding)
91-
return rounding
217+
configure_power(power)
218+
configure_matmul(matmul)
219+
return numtype, flavor, rounding, power, matmul
92220
end
93221

94222
configure()
95223

96224
#
97225

226+
include("symbols.jl")
227+
228+
#
229+
98230
bareinterval(::Type{BigFloat}, a::AbstractIrrational) = _unsafe_bareinterval(BigFloat, a, a)
99231

100232
# Note: generated functions must be defined after all the methods they use

src/intervals/arithmetic/absmax.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Implement the square absolute value.
2727
This function calls `^` internally, hence it depends on
2828
`IntervalArithmetic.power_mode()`.
2929
"""
30-
Base.abs2(x::BareInterval) = _select_pown(power_mode(), x, 2) # not in the IEEE Standard 1788-2015
30+
Base.abs2(x::BareInterval) = _select_pown(x, 2) # not in the IEEE Standard 1788-2015
3131

3232
function Base.abs2(x::Interval)
3333
r = abs2(bareinterval(x))

src/intervals/arithmetic/power.jl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Available mode types:
2020
"""
2121
struct PowerMode{T} end
2222

23-
power_mode() = PowerMode{:fast}()
23+
#
2424

2525
"""
2626
^(x::BareInterval, y::BareInterval)
@@ -49,13 +49,13 @@ Interval{Float64}(-Inf, Inf, trv)
4949
```
5050
"""
5151
function Base.:^(x::BareInterval, y::BareInterval)
52-
isthininteger(y) || return _select_pow(power_mode(), x, y)
53-
return _select_pown(power_mode(), x, Integer(sup(y)))
52+
isthininteger(y) || return _select_pow(x, y)
53+
return _select_pown(x, Integer(sup(y)))
5454
end
5555

5656
function Base.:^(x::Interval, y::Interval)
57-
isthininteger(y) || return _select_pow(power_mode(), x, y)
58-
r = _select_pown(power_mode(), x, Integer(sup(y)))
57+
isthininteger(y) || return _select_pow(x, y)
58+
r = _select_pown(x, Integer(sup(y)))
5959
d = min(decoration(r), decoration(y))
6060
t = isguaranteed(r) & isguaranteed(y)
6161
return _unsafe_interval(bareinterval(r), d, t)
@@ -65,7 +65,7 @@ Base.:^(x::Interval, n::Integer) = ^(x, n//one(n))
6565
Base.:^(x::Interval, y::Rational) = ^(x, convert(Interval{typeof(y)}, y))
6666

6767
function Base.:^(x::Complex{<:Interval}, y::Complex{<:Interval})
68-
if isreal(x) && isthininteger(y)
68+
if isthinzero(imag(x)) && isthininteger(y)
6969
r = real(x) ^ real(y)
7070
d = min(decoration(x), decoration(y), decoration(r))
7171
t = isguaranteed(x) & isguaranteed(y)
@@ -96,7 +96,7 @@ Base.:^(x::Complex{<:Interval}, y::Interval) = ^(promote(x, y)...)
9696
Base.:^(x::Interval, y::Complex{<:Interval}) = ^(promote(x, y)...)
9797

9898
# overwrite behaviour for small integer powers from https://github.com/JuliaLang/julia/pull/24240
99-
Base.literal_pow(::typeof(^), x::Interval, ::Val{n}) where {n} = _select_pown(power_mode(), x, n)
99+
Base.literal_pow(::typeof(^), x::Interval, ::Val{n}) where {n} = _select_pown(x, n)
100100
Base.literal_pow(::typeof(^), x::Complex{<:Interval}, ::Val{n}) where {n} = ^(x, interval(n))
101101

102102
# helper functions for power
@@ -310,9 +310,9 @@ Compute the hypotenuse.
310310
311311
Implement the `hypot` function of the IEEE Standard 1788-2015 (Table 10.5).
312312
"""
313-
Base.hypot(x::BareInterval, y::BareInterval) = sqrt(_select_pown(power_mode(), x, 2) + _select_pown(power_mode(), y, 2))
313+
Base.hypot(x::BareInterval, y::BareInterval) = sqrt(_select_pown(x, 2) + _select_pown(y, 2))
314314

315-
Base.hypot(x::Interval, y::Interval) = sqrt(_select_pown(power_mode(), x, 2) + _select_pown(power_mode(), y, 2))
315+
Base.hypot(x::Interval, y::Interval) = sqrt(_select_pown(x, 2) + _select_pown(y, 2))
316316

317317
"""
318318
fastpow(x, y)

src/intervals/construction.jl

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,6 @@ Constant for the supported types of interval bounds. This is set to
88
"""
99
const NumTypes = Union{Rational,AbstractFloat}
1010

11-
"""
12-
default_numtype()
13-
14-
Return the default bound type used in [`promote_numtype`](@ref). By default,
15-
`default_numtype()` is set to `Float64`. It can be modified by redefining the
16-
function, however it should be set to a concrete subtype of [`NumTypes`](@ref).
17-
18-
# Examples
19-
20-
```jldoctest
21-
julia> IntervalArithmetic.default_numtype() = Float32
22-
23-
julia> typeof(interval(1, 2))
24-
Interval{Float32}
25-
26-
julia> typeof(interval(1, big(2)))
27-
Interval{BigFloat}
28-
29-
julia> IntervalArithmetic.default_numtype() = Float64
30-
31-
julia> typeof(interval(1, 2))
32-
Interval{Float64}
33-
34-
julia> typeof(interval(1, big(2)))
35-
Interval{BigFloat}
36-
```
37-
"""
38-
default_numtype() = Float64
39-
4011
"""
4112
promote_numtype(T, S)
4213
@@ -45,12 +16,11 @@ Return the bound type used to construct intervals. The bound type is given by
4516
when `T` is a `Rational{R}` and `S` is an `AbstractIrrational` (or vice-versa),
4617
in which case the bound type is given by `Rational{promote_type(R, Int64)}`. In
4718
all other cases, the bound type is given by
48-
`promote_type(default_numtype(), T, S)`.
19+
`promote_type([DEFAULT BOUND TYPE], T, S)`.
4920
"""
5021
promote_numtype(::Type{T}, ::Type{S}) where {T<:NumTypes,S<:NumTypes} = promote_type(T, S)
5122
promote_numtype(::Type{T}, ::Type{S}) where {T<:NumTypes,S} = promote_type(numtype(T), numtype(S))
5223
promote_numtype(::Type{T}, ::Type{S}) where {T,S<:NumTypes} = promote_type(numtype(T), numtype(S))
53-
promote_numtype(::Type{T}, ::Type{S}) where {T,S} = promote_type(default_numtype(), numtype(T), numtype(S))
5424

5525
promote_numtype(::Type{Rational{T}}, ::Type{<:AbstractIrrational}) where {T<:Integer} = Rational{promote_type(T, Int64)}
5626
promote_numtype(::Type{<:AbstractIrrational}, ::Type{Rational{T}}) where {T<:Integer} = Rational{promote_type(T, Int64)}
@@ -659,10 +629,6 @@ julia> @interval Float64 sin(1) exp(1)
659629
Interval{Float64}(0.8414709848078965, 2.7182818284590455, com)
660630
```
661631
"""
662-
macro interval(expr)
663-
return _wrap_interval(default_numtype(), expr)
664-
end
665-
666632
macro interval(T, expr)
667633
return _wrap_interval(T, expr)
668634
end

src/intervals/flavor.jl

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ Some flavors `F` include:
2828
# Examples
2929
3030
```jldoctest
31-
julia> IntervalArithmetic.default_flavor()
32-
IntervalArithmetic.Flavor{:set_based}()
33-
3431
julia> IntervalArithmetic.is_valid_interval(Inf, Inf)
3532
false
3633
@@ -49,50 +46,37 @@ true
4946
"""
5047
struct Flavor{F} end
5148

52-
"""
53-
default_flavor()
54-
55-
Return the default flavor used to handle edge cases.
56-
"""
57-
default_flavor() = Flavor{:set_based}()
49+
#
5850

5951
"""
60-
zero_times_infinity([F::Flavor=default_flavor()], T<:NumTypes)
52+
zero_times_infinity([F::Flavor,] T<:NumTypes)
6153
6254
For the given flavor `F`, return ``0 \\times \\infty`` as an instance of type
6355
`T`.
6456
"""
6557
zero_times_infinity(::Flavor{:set_based}, ::Type{T}) where {T<:NumTypes} = zero(T)
6658

67-
zero_times_infinity(::Type{T}) where {T<:NumTypes} = zero_times_infinity(default_flavor(), T)
68-
6959
"""
70-
div_by_thin_zero([F::Flavor=default_flavor()], x::BareInterval)
60+
div_by_thin_zero([F::Flavor,] x::BareInterval)
7161
7262
For the given flavor `F`, divide `x` by the interval containing only ``0``.
7363
"""
7464
div_by_thin_zero(::Flavor{:set_based}, ::BareInterval{T}) where {T<:NumTypes} =
7565
emptyinterval(BareInterval{T})
7666

77-
div_by_thin_zero(x::BareInterval) = div_by_thin_zero(default_flavor(), x)
78-
7967
"""
80-
contains_infinity([F::Flavor=default_flavor()], x::BareInterval)
68+
contains_infinity([F::Flavor,] x::BareInterval)
8169
8270
For the given flavor `F`, test whether `x` contains infinity.
8371
"""
8472
contains_infinity(::Flavor{:set_based}, ::BareInterval) = false
8573

86-
contains_infinity(x::BareInterval) = contains_infinity(default_flavor(), x)
87-
8874
"""
89-
is_valid_interval([F::Flavor=default_flavor()], a::Real, b::Real)
75+
is_valid_interval([F::Flavor,] a::Real, b::Real)
9076
9177
For the given flavor `F`, test whether ``[a, b]`` is a valid interval.
9278
"""
9379
is_valid_interval(::Flavor{:set_based}, a::Real, b::Real) = b - a 0
9480
# to prevent issues with division by zero, e.g. `is_valid_interval(1//0, 1//0)`
9581
is_valid_interval(::Flavor{:set_based}, a::Rational, b::Rational) =
9682
!((a > b) | (a == typemax(typeof(a))) | (b == typemin(typeof(b))))
97-
98-
is_valid_interval(a::Real, b::Real) = is_valid_interval(default_flavor(), a, b)

0 commit comments

Comments
 (0)