diff --git a/src/RangeEnclosures.jl b/src/RangeEnclosures.jl index 8d62eef8..d3b0f34c 100644 --- a/src/RangeEnclosures.jl +++ b/src/RangeEnclosures.jl @@ -13,6 +13,7 @@ const Interval_or_IntervalVector_or_IntervalBox = Union{Interval,AbstractVector{ const IntervalVector_or_IntervalBox = Union{AbstractVector{<:Interval},IntervalBox} using ReachabilityBase.Require +include("wrap_output.jl") include("algorithms.jl") include("intervalarithmetic.jl") include("branchandbound.jl") @@ -25,7 +26,10 @@ include("intervaloptimisation.jl") # ================ function __init__() - @require AffineArithmetic = "2e89c364-fad6-56cb-99bd-ebadcd2cf8d2" eval(load_affinearithmetic()) + @require AffineArithmetic = "2e89c364-fad6-56cb-99bd-ebadcd2cf8d2" begin + eval(load_affinearithmetic()) + eval(load_affinearithmetic_wrap_output()) + end @require SumOfSquares = "4b9e565b-77fc-50a5-a571-1244f986bda1" include("sdp.jl") @require TaylorModels = "314ce334-5f6e-57ae-acf6-00b6e903104a" eval(load_taylormodels()) @require IntervalOptimisation = "c7c68f13-a4a2-5b9a-b424-07d005f8d9d2" eval(load_intervaloptimization()) diff --git a/src/affine.jl b/src/affine.jl index ecebc388..85630145 100644 --- a/src/affine.jl +++ b/src/affine.jl @@ -13,7 +13,7 @@ function enclose(f::Function, dom::Interval, ::AffineArithmeticEnclosure) require(@__MODULE__, :AffineArithmetic; fun_name="enclose") x = Aff(dom, 1, 1) - return interval(f(x)) + return _wrap_output(f(x)) end # multivariate @@ -21,7 +21,7 @@ function _enclose(::AffineArithmeticEnclosure, f::Function, dom::IntervalVector_ require(@__MODULE__, :AffineArithmetic; fun_name="enclose") x = [Aff(dom[i], N, i) for i in 1:N] - return interval(f(x)) + return _wrap_output(f(x)) end function enclose(f::Function, dom::AbstractVector{<:Interval}, aae::AffineArithmeticEnclosure) diff --git a/src/enclose.jl b/src/enclose.jl index cbcae58b..7bea8734 100644 --- a/src/enclose.jl +++ b/src/enclose.jl @@ -39,12 +39,13 @@ julia> enclose(x -> 1 - x^4 + x^5, interval(0, 1), [TaylorModelsEnclosure(), Nat ``` """ function enclose(f::Function, dom::Interval_or_IntervalVector_or_IntervalBox; kwargs...) - return enclose(f, dom, NaturalEnclosure(); kwargs...) + return _wrap_output(enclose(f, dom, NaturalEnclosure(); kwargs...)) end function enclose(f::Function, dom::Interval_or_IntervalVector_or_IntervalBox, solvers::Vector; kwargs...) - return mapreduce(solver -> enclose(f, dom, solver; kwargs...), intersect_interval, solvers) + return _wrap_output(mapreduce(solver -> enclose(f, dom, solver; kwargs...), intersect_interval, + solvers)) end """ diff --git a/src/intervalarithmetic.jl b/src/intervalarithmetic.jl index 826fbd85..624c46e8 100644 --- a/src/intervalarithmetic.jl +++ b/src/intervalarithmetic.jl @@ -5,7 +5,7 @@ # univariate and multivariate cases function enclose(f::Function, dom::Interval_or_IntervalVector_or_IntervalBox, ::NaturalEnclosure; kwargs...) - return f(dom) + return _wrap_output(f(dom)) end # univariate case diff --git a/src/taylormodels.jl b/src/taylormodels.jl index b902db45..7ba3aaa2 100644 --- a/src/taylormodels.jl +++ b/src/taylormodels.jl @@ -11,7 +11,7 @@ function enclose(f::Function, dom::Interval_or_IntervalVector_or_IntervalBox, else R = _enclose_TaylorModels(f, dom, tm.order) end - return R + return _wrap_output(R) end function load_taylormodels() @@ -21,11 +21,19 @@ function load_taylormodels() @inline zeroBox(N) = fill(interval(0, 0), N) @inline symBox(N) = fill(interval(-1, 1), N) + function _evaluate(tm::NTuple{N}, dom) where {N} + return evaluate.(tm, Ref(dom)) + end + + function _evaluate(tm, dom) + return evaluate(tm, dom) + end + # univariate function _enclose_TaylorModels(f::Function, dom::Interval, order::Int) x0 = interval(mid(dom)) x = TaylorModel1(order, x0, dom) - return evaluate(f(x - x0), dom) + return _evaluate(f(x - x0), dom) end # normalized univariate @@ -34,7 +42,7 @@ function load_taylormodels() x = TaylorModel1(order, x0, dom) xnorm = normalize_taylor(x.pol, dom - x0, true) xnormTM = TaylorModel1(xnorm, interval(0, 0), interval(0, 0), interval(-1, 1)) - return evaluate(f(xnormTM), interval(-1, 1)) + return _evaluate(f(xnormTM), interval(-1, 1)) end # multivariate @@ -43,7 +51,7 @@ function load_taylormodels() x0 = [interval(mid(di)) for di in dom] set_variables(Float64, "x"; order=2order, numvars=N) x = [TaylorModelN(i, order, x0, dom) for i in 1:N] - return evaluate(f(x), dom - x0) + return _evaluate(f(x), dom - x0) end function _enclose_TaylorModels(f::Function, dom::IntervalBox, order::Int) @@ -62,7 +70,7 @@ function load_taylormodels() x = [TaylorModelN(i, order, x0, dom) for i in 1:N] xnorm = [normalize_taylor(xi.pol, dom - x0, true) for xi in x] xnormTM = [TaylorModelN(xi_norm, interval(0, 0), zBoxN, sBoxN) for xi_norm in xnorm] - return evaluate(f(xnormTM), sBoxN) + return _evaluate(f(xnormTM), sBoxN) end function _enclose_TaylorModels_norm(f::Function, dom::IntervalBox{N}, order::Int) where {N} diff --git a/src/wrap_output.jl b/src/wrap_output.jl new file mode 100644 index 00000000..89464c3d --- /dev/null +++ b/src/wrap_output.jl @@ -0,0 +1,20 @@ +# internal helper function to wrap a tuple output +function _wrap_output(x::NTuple{N,Interval}) where {N} + return collect(x) +end + +function _wrap_output(x::Interval_or_IntervalVector) + return x +end + +function load_affinearithmetic_wrap_output() + return quote + function _wrap_output(x::NTuple{N,Aff}) where {N} + return collect(interval.(x)) + end + + function _wrap_output(x::Aff) + return interval(x) + end + end # quote +end # load_affinearithmetic_wrap_output() diff --git a/test/multivariate.jl b/test/multivariate.jl index f48b004a..4a6b979d 100644 --- a/test/multivariate.jl +++ b/test/multivariate.jl @@ -32,6 +32,23 @@ end @test rleft ≤ 1e-5 && rright ≤ 1e-5 end +@testset "Multivariate input, multivariate output" begin + f(x) = (-x[1], 2 * x[2]) + dIB = IntervalBox(1..2, 3..4) + for dom in (dIB, Vector(dIB.v)) + for solver in available_solvers + if (solver isa MeanValueEnclosure || solver isa MooreSkelboeEnclosure || + solver isa BranchAndBoundEnclosure) + # solver does not support multivariate outputs + continue + end + x = enclose(f, dom, solver) + @test x isa Vector{Interval{Float64}} + @test issubset_interval([interval(-2, -1), interval(6, 8)], x) + end + end +end + @testset "Test multivariate polynomial input" begin @polyvar x y p = (x + 2y - 7)^2 + (2x + y - 5)^2 diff --git a/test/univariate.jl b/test/univariate.jl index 71183240..15937203 100644 --- a/test/univariate.jl +++ b/test/univariate.jl @@ -45,6 +45,21 @@ end @test rleft ≤ 1e-5 && rright ≤ 1e-5 end +@testset "Univariate input, multivariate output" begin + f(x) = (-x, 3x) + dom = interval(-1, 2) + for solver in available_solvers + if (solver isa MeanValueEnclosure || solver isa MooreSkelboeEnclosure || + solver isa BranchAndBoundEnclosure) + # solver does not support multivariate outputs + continue + end + x = enclose(f, dom, solver) + @test x isa Vector{Interval{Float64}} + @test issubset_interval([interval(-2, 1), interval(-3, 6)], x) + end +end + @testset "Test univariate polynomial input" begin @polyvar x p = -x^3 / 6 + 5x