From b364c38607ce9b237f3eb6fff251b02358b8db50 Mon Sep 17 00:00:00 2001 From: Yashvardhan Sharma <31127446+yashcodes@users.noreply.github.com> Date: Sun, 24 Feb 2019 13:46:58 +0530 Subject: [PATCH 01/11] Adding HeapedVector.jl (#28) * Adding HeapedVector.jl and adding benchmarks * trying to import Strategy.jl but cant do it * Error:In Extending the function of StrategyBase.jl * Tests and some bugs are fixed * Benchmarks is shift to another branch * .DS_store is removedand made few changes in Heaped and SortedVector * All .DS_Store files are removed --- src/HeapedVectors.jl | 107 ++++++++++++++++++++++++++++++++++++ src/IntervalOptimisation.jl | 11 +++- src/SortedVectors.jl | 22 ++++---- src/StrategyBase.jl | 7 +++ src/optimise.jl | 31 ++++++----- test/heaped_vector.jl | 36 ++++++++++++ test/optimise.jl | 54 ++++++++++++------ test/runtests.jl | 3 +- test/sorted_vector.jl | 2 +- 9 files changed, 224 insertions(+), 49 deletions(-) create mode 100644 src/HeapedVectors.jl create mode 100644 src/StrategyBase.jl create mode 100644 test/heaped_vector.jl diff --git a/src/HeapedVectors.jl b/src/HeapedVectors.jl new file mode 100644 index 0000000..98f2092 --- /dev/null +++ b/src/HeapedVectors.jl @@ -0,0 +1,107 @@ +__precompile__() + +module HeapedVectors + +import Base: getindex, length, push!, isempty, + pop!, filter!, popfirst! + +export HeapedVector + +import ..StrategyBase:filter_elements! +using ..StrategyBase + +struct HeapedVector{T, F<:Function} <: Strategy + data::Vector{T} + by::F + function HeapedVector(v::Vector{T}, by::F) where {T, F} + new{T, F}(heaping(v, by), by) + end +end + +HeapedVector(data::Vector{T}) where {T} = HeapedVector(data, identity) + + +function heaping(v, by) + ar = typeof(v[1])[] + for i = 1:length(v) + insert!(ar, i, v[i]) + floatup!(ar, length(ar), by) + end + return ar +end + +function floatup!(ar, index, by) + par = convert(Int, floor(index/2)) + if index <= 1 + return ar + end + if by(ar[index]) < by(ar[par]) + ar[par], ar[index] = ar[index], ar[par] + end + floatup!(ar, par, by) +end + + +function push!(v::HeapedVector{T}, x::T) where {T} + insert!(v.data, length(v.data)+1, x) + floatup!(v.data, length(v.data), v.by) + return v +end + + +isempty(v::HeapedVector) = isempty(v.data) + + +function popfirst!(v::HeapedVector{T}) where {T} + if length(v.data) == 0 + return + end + + if length(v.data) > 2 + v.data[length(v.data)], v.data[1] = v.data[1], v.data[length(v.data)] + minm = pop!(v.data) + bubbledown!(v::HeapedVector{T}, 1) + + elseif length(v.data) == 2 + v.data[length(v.data)], v.data[1] = v.data[1], v.data[length(v.data)] + minm = pop!(v.data) + else + minm = pop!(v.data) + end + return minm +end + + +function bubbledown!(v::HeapedVector{T}, index) where{T} + left = index*2 + right = index*2+1 + smallest = index + + if length(v.data)+1 > left && v.by(v.data[smallest]) > v.by(v.data[left]) + smallest = left + end + + if length(v.data)+1 > right && v.by(v.data[smallest]) > v.by(v.data[right]) + smallest = right + end + + if smallest != index + v.data[index], v.data[smallest] = v.data[smallest], v.data[index] + bubbledown!(v, smallest) + end +end + +function filter_elements!(A::HeapedVector{T}, x::T) where{T} + func(y) = A.by(y) < A.by(x) + filter!(func, A.data) + + if length(A.data) == 0 + return A + end + + heaping(A.data, A.by) + return A + +end + +end diff --git a/src/IntervalOptimisation.jl b/src/IntervalOptimisation.jl index 65cd52c..314e797 100644 --- a/src/IntervalOptimisation.jl +++ b/src/IntervalOptimisation.jl @@ -1,18 +1,23 @@ - - module IntervalOptimisation export minimise, maximise, minimize, maximize +export HeapedVector, SortedVector + +include("StrategyBase.jl") +using .StrategyBase include("SortedVectors.jl") using .SortedVectors -using IntervalArithmetic, IntervalRootFinding +include("HeapedVectors.jl") +using .HeapedVectors +using IntervalArithmetic, IntervalRootFinding include("optimise.jl") + const minimize = minimise const maximize = maximise diff --git a/src/SortedVectors.jl b/src/SortedVectors.jl index 93b8dfb..c42dea7 100644 --- a/src/SortedVectors.jl +++ b/src/SortedVectors.jl @@ -3,31 +3,29 @@ __precompile__() module SortedVectors import Base: getindex, length, push!, isempty, - pop!, resize!, popfirst! + pop!, popfirst! export SortedVector -""" -A `SortedVector` behaves like a standard Julia `Vector`, except that its elements are stored in sorted order, with an optional function `by` that determines the sorting order in the same way as `Base.searchsorted`. -""" -struct SortedVector{T, F<:Function} +import ..StrategyBase:filter_elements! +using ..StrategyBase + +struct SortedVector{T, F<:Function} <: Strategy + data::Vector{T} by::F function SortedVector(data::Vector{T}, by::F) where {T,F} - new{T,F}(sort(data,by=by), by) + new{T,F}(sort(data, by = by), by) end end - SortedVector(data::Vector{T}) where {T} = SortedVector(data, identity) function show(io::IO, v::SortedVector) print(io, "SortedVector($(v.data))") end - - getindex(v::SortedVector, i::Int) = v.data[i] length(v::SortedVector) = length(v.data) @@ -43,9 +41,9 @@ pop!(v::SortedVector) = pop!(v.data) popfirst!(v::SortedVector) = popfirst!(v.data) - -function resize!(v::SortedVector, n::Int) - resize!(v.data, n) +function filter_elements!(v::SortedVector{T}, x::T) where {T} + cutoff = searchsortedfirst(v.data, x, by=v.by) + resize!(v.data, cutoff-1) return v end diff --git a/src/StrategyBase.jl b/src/StrategyBase.jl new file mode 100644 index 0000000..b88e833 --- /dev/null +++ b/src/StrategyBase.jl @@ -0,0 +1,7 @@ +module StrategyBase + + export filter_elements!, Strategy + abstract type Strategy end + function filter_elements!(s::Strategy)end + +end diff --git a/src/optimise.jl b/src/optimise.jl index 4629811..a184217 100644 --- a/src/optimise.jl +++ b/src/optimise.jl @@ -1,18 +1,22 @@ +""" + minimise(f, X, structure = SortedVector, tol=1e-3) + or + minimise(f, X, structure = HeapedVector, tol=1e-3) + or + minimise(f, X, tol=1e-3) in this case the default value of "structure" is "HeapedVector" -""" - minimise(f, X, tol=1e-3) - -Find the global minimum of the function `f` over the `Interval` or `IntervalBox` `X` using the Moore-Skelboe algorithm. +Find the global minimum of the function `f` over the `Interval` or `IntervalBox` `X` using the Moore-Skelboe algorithm. By specifing the way in which vector element are kept arranged which is in heaped array or in sorted array. If you not specify any particular strategy to keep vector elements arranged then by default heaped array is used. For higher-dimensional functions ``f:\\mathbb{R}^n \\to \\mathbb{R}``, `f` must take a single vector argument. Returns an interval containing the global minimum, and a list of boxes that contain the minimisers. """ -function minimise(f, X::T, tol=1e-3) where {T} - # list of boxes with corresponding lower bound, ordered by increasing lower bound: - working = SortedVector([(X, ∞)], x->x[2]) +function minimise(f, X::T ; structure = HeapedVector, tol=1e-3 ) where {T} + + # list of boxes with corresponding lower bound, arranged according to selected structure : + working = structure([(X, ∞)], x->x[2]) minimizers = T[] global_min = ∞ # upper bound @@ -34,17 +38,14 @@ function minimise(f, X::T, tol=1e-3) where {T} end # Remove all boxes whose lower bound is greater than the current one: - # Since they are ordered, just find the first one that is too big - - cutoff = searchsortedfirst(working.data, (X, global_min), by=x->x[2]) - resize!(working, cutoff-1) + filter_elements!(working , (X, global_min) ) if diam(X) < tol push!(minimizers, X) - else X1, X2 = bisect(X) - push!( working, (X1, inf(f(X1))), (X2, inf(f(X2))) ) + push!( working, (X1, inf(f(X1))) ) + push!( working, (X2, inf(f(X2))) ) num_bisections += 1 end @@ -56,7 +57,7 @@ function minimise(f, X::T, tol=1e-3) where {T} end -function maximise(f, X::T, tol=1e-3) where {T} - bound, minimizers = minimise(x -> -f(x), X, tol) +function maximise(f, X::T; structure = HeapedVector, tol=1e-3 ) where {T} + bound, minimizers = minimise(x -> -f(x), X, structure, tol) return -bound, minimizers end diff --git a/test/heaped_vector.jl b/test/heaped_vector.jl new file mode 100644 index 0000000..b65e1b3 --- /dev/null +++ b/test/heaped_vector.jl @@ -0,0 +1,36 @@ +using IntervalOptimisation +using Test + +const HeapedVector = IntervalOptimisation.HeapedVector + +@testset "heap" begin + + @testset "with standard heaping " begin + + h=HeapedVector([9, 7, 5, 2, 3]) + + @test h.data == [2, 3, 7, 9, 5] + + push!(h, 1) + @test h.data == [1, 3, 2, 9, 5, 7] + + popfirst!(h) + @test h.data == [2, 3, 7, 9, 5] + + end + + @testset "with ordering function" begin + + h=HeapedVector( [(9,"f"), (7,"c"), (5,"e"), (2,"d"), (3,"b")] , x->x[2]) + + @test h.data == [(3, "b"), (7, "c"), (5, "e"), (9, "f"), (2, "d")] + + push!(h, (1,"a")) + @test h.data == [(1, "a"), (7, "c"), (3, "b"), (9, "f"), (2, "d"), (5, "e")] + + popfirst!(h) + @test h.data == [(3, "b"), (7, "c"), (5, "e"), (9, "f"), (2, "d")] + + end + +end \ No newline at end of file diff --git a/test/optimise.jl b/test/optimise.jl index 641c1f2..7aaf96c 100644 --- a/test/optimise.jl +++ b/test/optimise.jl @@ -1,15 +1,15 @@ -using IntervalArithmetic, IntervalOptimisation +using IntervalArithmetic, IntervalOptimisation using Test @testset "IntervalOptimisation tests" begin - @testset "Minimise in 1D" begin + @testset "Minimise in 1D using default data structure i.e HeapedVector" begin global_min, minimisers = minimise(x->x, -10..10) @test global_min ⊆ -10 .. -9.999 @test length(minimisers) == 1 @test minimisers[1] ⊆ -10 .. -9.999 - global_min, minimisers = minimise(x->x^2, -10..11, 1e-10) + global_min, minimisers = minimise(x->x^2, -10..11, tol = 1e-10) @test global_min ⊆ 0..1e-20 @test length(minimisers) == 1 @test minimisers[1] ⊆ -0.1..0.1 @@ -17,26 +17,46 @@ using Test global_min, minimisers = minimise(x->(x^2-2)^2, -10..11) @test global_min ⊆ 0..1e-7 @test length(minimisers) == 2 - @test sqrt(2) ∈ minimisers[1] + @test sqrt(2) ∈ minimisers[2] end + for Structure in (SortedVector, HeapedVector) - @testset "Discontinuous function in 1D" begin + @testset "Minimise in 1D using SoretedVector" begin + global_min, minimisers = minimise(x->x, -10..10, structure = Structure) + @test global_min ⊆ -10 .. -9.999 + @test length(minimisers) == 1 + @test minimisers[1] ⊆ -10 .. -9.999 - H(x) = (sign(x) + 1) / 2 # Heaviside function except at 0, where H(0) = 0.5 + global_min, minimisers = minimise(x->x^2, -10..11, tol=1e-10, structure = Structure) + @test global_min ⊆ 0..1e-20 + @test length(minimisers) == 1 + @test minimisers[1] ⊆ -0.1..0.1 - global_min, minimisers = minimise(x -> abs(x) + H(x) - 1, -10..11, 1e-5) - @test global_min ⊆ -1 .. -0.9999 - @test length(minimisers) == 1 - @test 0 ∈ minimisers[1] - @test diam(minimisers[1]) <= 1e-5 - end + global_min, minimisers = minimise(x->(x^2-2)^2, -10..11, structure = Structure) + @test global_min ⊆ 0..1e-7 + @test length(minimisers) == 2 + @test sqrt(2) ∈ max(minimisers[1], minimisers[2]) + end - @testset "Smooth function in 2D" begin - global_min, minimisers = minimise( X -> ( (x,y) = X; x^2 + y^2 ), (-10..10) × (-10..10) ) - @test global_min ⊆ 0..1e-7 - @test all(X ⊆ (-1e-3..1e3) × (-1e-3..1e-3) for X in minimisers) + @testset "Discontinuous function in 1D" begin + + H(x) = (sign(x) + 1) / 2 # Heaviside function except at 0, where H(0) = 0.5 + global_min, minimisers = minimise(x -> abs(x) + H(x) - 1, -10..11, tol=1e-5, structure = Structure) + @test global_min ⊆ -1 .. -0.9999 + @test length(minimisers) == 1 + @test 0 ∈ minimisers[1] + @test diam(minimisers[1]) <= 1e-5 + end + + + @testset "Smooth function in 2D" begin + global_min, minimisers = minimise( X -> ( (x,y) = X; x^2 + y^2 ), (-10..10) × (-10..10), structure = Structure ) + @test global_min ⊆ 0..1e-7 + @test all(X ⊆ (-1e-3..1e3) × (-1e-3..1e-3) for X in minimisers) + end + end -end +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index cadea80..e50374e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,4 +2,5 @@ using IntervalOptimisation using Test include("sorted_vector.jl") -include("optimise.jl") +include("heaped_vector.jl") +include("optimise.jl") \ No newline at end of file diff --git a/test/sorted_vector.jl b/test/sorted_vector.jl index 70413f2..f1ca3d6 100644 --- a/test/sorted_vector.jl +++ b/test/sorted_vector.jl @@ -47,4 +47,4 @@ const SortedVector = IntervalOptimisation.SortedVector @test v.data == [(1, "a"), (4, "c"), (3, "x"), (5, "y"), (2, "z")] end -end +end \ No newline at end of file From 09b52a4721dbd9457ca7e710507b92c8e6f1edd0 Mon Sep 17 00:00:00 2001 From: Yashvardhan Sharma <31127446+yashcodes@users.noreply.github.com> Date: Tue, 4 Jun 2019 20:55:19 +0530 Subject: [PATCH 02/11] Adding Project.toml (#35) * Adding Project.toml * few additions * Correct comment in NEWS.md --- NEWS.md | 3 +++ Project.toml | 24 ++++++++++++++++++++++++ REQUIRE | 7 ------- 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 Project.toml delete mode 100644 REQUIRE diff --git a/NEWS.md b/NEWS.md index 97b117c..3dc4f92 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # NEWS for IntervalOptimisation.jl +## v0.4 +- Drop support for Julia 0.7 + ## v0.3 - Drop support for Julia 0.6. The package is now fully compatible with Julia 1.0. diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000..49498eb --- /dev/null +++ b/Project.toml @@ -0,0 +1,24 @@ +name = "IntervalOptimisation" +uuid = "c7c68f13-a4a2-5b9a-b424-07d005f8d9d2" +version = "0.4.0" + +[compat] +DataStructures = "≥ 0.9.0" +ForwardDiff = "≥ 0.8.0" +IntervalArithmetic = "≥ 0.15.0" +IntervalConstraintProgramming = "≥ 0.9.0" +IntervalRootFinding = "≥ 0.4.0" +julia = "≥ 1.0.0" + +[deps] +DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" +IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253" +IntervalConstraintProgramming = "138f1668-1576-5ad7-91b9-7425abbf3153" +IntervalRootFinding = "d2bf35a9-74e0-55ec-b149-d360ff49b807" + +[extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Test"] diff --git a/REQUIRE b/REQUIRE deleted file mode 100644 index 3161ea8..0000000 --- a/REQUIRE +++ /dev/null @@ -1,7 +0,0 @@ -julia 0.7 - -IntervalArithmetic 0.15 -IntervalRootFinding 0.4 -IntervalConstraintProgramming 0.9 -DataStructures 0.9 -ForwardDiff 0.8 From f28247fd9654008929df2427d85fc7efca29cde3 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Wed, 10 Jul 2019 17:27:07 -0300 Subject: [PATCH 03/11] min and max docstrings (#38) --- src/optimise.jl | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/optimise.jl b/src/optimise.jl index a184217..f301d51 100644 --- a/src/optimise.jl +++ b/src/optimise.jl @@ -5,15 +5,17 @@ or minimise(f, X, tol=1e-3) in this case the default value of "structure" is "HeapedVector" -Find the global minimum of the function `f` over the `Interval` or `IntervalBox` `X` using the Moore-Skelboe algorithm. By specifing the way in which vector element are kept arranged which is in heaped array or in sorted array. If you not specify any particular strategy to keep vector elements arranged then by default heaped array is used. +Find the global minimum of the function `f` over the `Interval` or `IntervalBox` `X` +using the Moore-Skelboe algorithm. The way in which vector elements are +kept arranged can be either a heaped array or a sorted array. +If you not specify any particular strategy to keep vector elements arranged then +by default heaped array is used. For higher-dimensional functions ``f:\\mathbb{R}^n \\to \\mathbb{R}``, `f` must take a single vector argument. Returns an interval containing the global minimum, and a list of boxes that contain the minimisers. """ - - -function minimise(f, X::T ; structure = HeapedVector, tol=1e-3 ) where {T} +function minimise(f, X::T; structure = HeapedVector, tol=1e-3) where {T} # list of boxes with corresponding lower bound, arranged according to selected structure : working = structure([(X, ∞)], x->x[2]) @@ -56,8 +58,18 @@ function minimise(f, X::T ; structure = HeapedVector, tol=1e-3 ) where {T} return Interval(lower_bound, global_min), minimizers end +""" + maximise(f, X, structure = SortedVector, tol=1e-3) + or + maximise(f, X, structure = HeapedVector, tol=1e-3) + or + maximise(f, X, tol=1e-3) in this case the default value of "structure" is "HeapedVector" -function maximise(f, X::T; structure = HeapedVector, tol=1e-3 ) where {T} +Find the global maximum of the function `f` over the `Interval` or `IntervalBox` `X` +using the Moore-Skelboe algorithm. See [`minimise`](@ref) for a description +of the available options. +""" +function maximise(f, X::T; structure = HeapedVector, tol=1e-3) where {T} bound, minimizers = minimise(x -> -f(x), X, structure, tol) return -bound, minimizers end From 32027e9e3417aa8dd0fea62ebf2490cffc1bdfc4 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Fri, 19 Jul 2019 17:13:10 -0300 Subject: [PATCH 04/11] add kwargs to maximise and tests (#40) --- src/optimise.jl | 4 ++-- test/optimise.jl | 22 ++++++++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/optimise.jl b/src/optimise.jl index f301d51..7b1be42 100644 --- a/src/optimise.jl +++ b/src/optimise.jl @@ -69,7 +69,7 @@ Find the global maximum of the function `f` over the `Interval` or `IntervalBox` using the Moore-Skelboe algorithm. See [`minimise`](@ref) for a description of the available options. """ -function maximise(f, X::T; structure = HeapedVector, tol=1e-3) where {T} - bound, minimizers = minimise(x -> -f(x), X, structure, tol) +function maximise(f, X::T; structure=HeapedVector, tol=1e-3) where {T} + bound, minimizers = minimise(x -> -f(x), X, structure=structure, tol=tol) return -bound, minimizers end diff --git a/test/optimise.jl b/test/optimise.jl index 7aaf96c..2633dfe 100644 --- a/test/optimise.jl +++ b/test/optimise.jl @@ -1,4 +1,4 @@ -using IntervalArithmetic, IntervalOptimisation +using IntervalArithmetic, IntervalOptimisation using Test @testset "IntervalOptimisation tests" begin @@ -9,6 +9,12 @@ using Test @test length(minimisers) == 1 @test minimisers[1] ⊆ -10 .. -9.999 + # same but with maximise + global_max, maximisers = maximise(x->x, -10..10) + @test global_max ⊆ 9.999 .. 10 + @test length(maximisers) == 1 + @test maximisers[1] ⊆ 9.999 .. 10 + global_min, minimisers = minimise(x->x^2, -10..11, tol = 1e-10) @test global_min ⊆ 0..1e-20 @test length(minimisers) == 1 @@ -28,6 +34,12 @@ using Test @test length(minimisers) == 1 @test minimisers[1] ⊆ -10 .. -9.999 + # same but with maximise + global_max, maximisers = maximise(x->x, -10..10, structure = Structure) + @test global_max ⊆ 9.999 .. 10 + @test length(maximisers) == 1 + @test maximisers[1] ⊆ 9.999 .. 10 + global_min, minimisers = minimise(x->x^2, -10..11, tol=1e-10, structure = Structure) @test global_min ⊆ 0..1e-20 @test length(minimisers) == 1 @@ -55,8 +67,14 @@ using Test global_min, minimisers = minimise( X -> ( (x,y) = X; x^2 + y^2 ), (-10..10) × (-10..10), structure = Structure ) @test global_min ⊆ 0..1e-7 @test all(X ⊆ (-1e-3..1e3) × (-1e-3..1e-3) for X in minimisers) + + # same but with maximise + global_max, maximisers = maximise( X -> ( (x,y) = X; x^2 + y^2 ), (-10..10) × (-10..10), structure = Structure ) + @test global_max ⊆ 199.9..200 + m = (9.99..10) + @test all(X ⊆ m × m || X ⊆ -m × m || X ⊆ m × -m || X ⊆ -m × -m for X in maximisers) end end -end \ No newline at end of file +end From 8c69987f68920192f9fa7d4270b778415348b3e7 Mon Sep 17 00:00:00 2001 From: Spencer Russell Date: Mon, 30 Sep 2019 19:30:30 -0400 Subject: [PATCH 05/11] Removes broken docs link from README (#41) --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 55f9dd0..37c7135 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,6 @@ [![appveyor badge][appveyor_badge]][appveyor_url] [![codecov badge][codecov_badge]][codecov_url] -## Documentation [here][documenter_latest] - [travis_badge]: https://travis-ci.org/JuliaIntervals/IntervalOptimisation.jl.svg?branch=master [travis_url]: https://travis-ci.org/JuliaIntervals/IntervalOptimisation.jl From 3476f3439fc0ff74f6f3598f1cbfc726ea17b3a6 Mon Sep 17 00:00:00 2001 From: Eric Hanson <5846501+ericphanson@users.noreply.github.com> Date: Sat, 14 Dec 2019 15:07:34 +0000 Subject: [PATCH 06/11] Allow optimizing over Bigfloat intervals (#45) * Allow bigfloat intervals * Add tests for `numeric_type` * Bump version * Remove unneeded dependencies, clean up --- Project.toml | 18 +++++------------- src/IntervalOptimisation.jl | 2 +- src/optimise.jl | 12 ++++++++---- test/heaped_vector.jl | 4 ++-- test/optimise.jl | 29 ++++++++++++++++++++++++++++- test/sorted_vector.jl | 4 ++-- 6 files changed, 46 insertions(+), 23 deletions(-) diff --git a/Project.toml b/Project.toml index 49498eb..b40860f 100644 --- a/Project.toml +++ b/Project.toml @@ -1,21 +1,13 @@ name = "IntervalOptimisation" uuid = "c7c68f13-a4a2-5b9a-b424-07d005f8d9d2" -version = "0.4.0" - -[compat] -DataStructures = "≥ 0.9.0" -ForwardDiff = "≥ 0.8.0" -IntervalArithmetic = "≥ 0.15.0" -IntervalConstraintProgramming = "≥ 0.9.0" -IntervalRootFinding = "≥ 0.4.0" -julia = "≥ 1.0.0" +version = "0.4.1" [deps] -DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253" -IntervalConstraintProgramming = "138f1668-1576-5ad7-91b9-7425abbf3153" -IntervalRootFinding = "d2bf35a9-74e0-55ec-b149-d360ff49b807" + +[compat] +IntervalArithmetic = "0.15, 0.16" +julia = "1.0" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/src/IntervalOptimisation.jl b/src/IntervalOptimisation.jl index 314e797..4fb2e93 100644 --- a/src/IntervalOptimisation.jl +++ b/src/IntervalOptimisation.jl @@ -13,7 +13,7 @@ using .SortedVectors include("HeapedVectors.jl") using .HeapedVectors -using IntervalArithmetic, IntervalRootFinding +using IntervalArithmetic include("optimise.jl") diff --git a/src/optimise.jl b/src/optimise.jl index 7b1be42..705936c 100644 --- a/src/optimise.jl +++ b/src/optimise.jl @@ -1,4 +1,7 @@ -""" +numeric_type(::Interval{T}) where {T} = T +numeric_type(::IntervalBox{N, T}) where {N, T} = T + +""" minimise(f, X, structure = SortedVector, tol=1e-3) or minimise(f, X, structure = HeapedVector, tol=1e-3) @@ -16,11 +19,12 @@ For higher-dimensional functions ``f:\\mathbb{R}^n \\to \\mathbb{R}``, `f` must Returns an interval containing the global minimum, and a list of boxes that contain the minimisers. """ function minimise(f, X::T; structure = HeapedVector, tol=1e-3) where {T} - + nT = numeric_type(X) + # list of boxes with corresponding lower bound, arranged according to selected structure : - working = structure([(X, ∞)], x->x[2]) + working = structure([(X, nT(∞))], x->x[2]) minimizers = T[] - global_min = ∞ # upper bound + global_min = nT(∞) # upper bound num_bisections = 0 diff --git a/test/heaped_vector.jl b/test/heaped_vector.jl index b65e1b3..02e0a38 100644 --- a/test/heaped_vector.jl +++ b/test/heaped_vector.jl @@ -1,7 +1,7 @@ using IntervalOptimisation using Test -const HeapedVector = IntervalOptimisation.HeapedVector +using IntervalOptimisation: HeapedVector @testset "heap" begin @@ -33,4 +33,4 @@ const HeapedVector = IntervalOptimisation.HeapedVector end -end \ No newline at end of file +end diff --git a/test/optimise.jl b/test/optimise.jl index 2633dfe..3377040 100644 --- a/test/optimise.jl +++ b/test/optimise.jl @@ -1,7 +1,16 @@ using IntervalArithmetic, IntervalOptimisation using Test +using IntervalOptimisation: numeric_type @testset "IntervalOptimisation tests" begin + @testset "numeric_type" begin + x = -10..10 + big_x = big(x) + @test numeric_type(x) == Float64 + @test numeric_type(big_x) == BigFloat + @test numeric_type(IntervalBox(x, x)) == Float64 + @test numeric_type(IntervalBox(big_x, big_x)) == BigFloat + end @testset "Minimise in 1D using default data structure i.e HeapedVector" begin global_min, minimisers = minimise(x->x, -10..10) @@ -15,6 +24,12 @@ using Test @test length(maximisers) == 1 @test maximisers[1] ⊆ 9.999 .. 10 + # same but with BigFloats + global_min, minimisers = minimise(x->x, -big(10.0)..big(10.0)) + @test global_min ⊆ -10 .. -9.999 + @test length(minimisers) == 1 + @test minimisers[1] ⊆ -10 .. -9.999 + global_min, minimisers = minimise(x->x^2, -10..11, tol = 1e-10) @test global_min ⊆ 0..1e-20 @test length(minimisers) == 1 @@ -28,7 +43,7 @@ using Test for Structure in (SortedVector, HeapedVector) - @testset "Minimise in 1D using SoretedVector" begin + @testset "Minimise in 1D using SortedVector" begin global_min, minimisers = minimise(x->x, -10..10, structure = Structure) @test global_min ⊆ -10 .. -9.999 @test length(minimisers) == 1 @@ -40,6 +55,12 @@ using Test @test length(maximisers) == 1 @test maximisers[1] ⊆ 9.999 .. 10 + # same but with BigFloats + global_min, minimisers = minimise(x->x, -big(10.0)..big(10.0), structure = Structure) + @test global_min ⊆ -10 .. -9.999 + @test length(minimisers) == 1 + @test minimisers[1] ⊆ -10 .. -9.999 + global_min, minimisers = minimise(x->x^2, -10..11, tol=1e-10, structure = Structure) @test global_min ⊆ 0..1e-20 @test length(minimisers) == 1 @@ -73,6 +94,12 @@ using Test @test global_max ⊆ 199.9..200 m = (9.99..10) @test all(X ⊆ m × m || X ⊆ -m × m || X ⊆ m × -m || X ⊆ -m × -m for X in maximisers) + + # same but with BigFloats + global_min, minimisers = minimise( X -> ( (x,y) = X; x^2 + y^2 ), (-big(10.0)..big(10.0)) × (-big(10.0)..big(10.0)), structure = Structure ) + @test global_min ⊆ 0..1e-7 + @test all(X ⊆ big(-1e-3..1e3) × big(-1e-3..1e-3) for X in minimisers) + end end diff --git a/test/sorted_vector.jl b/test/sorted_vector.jl index f1ca3d6..1358455 100644 --- a/test/sorted_vector.jl +++ b/test/sorted_vector.jl @@ -1,7 +1,7 @@ using IntervalOptimisation using Test -const SortedVector = IntervalOptimisation.SortedVector +using IntervalOptimisation: SortedVector @testset "SortedVector" begin @@ -47,4 +47,4 @@ const SortedVector = IntervalOptimisation.SortedVector @test v.data == [(1, "a"), (4, "c"), (3, "x"), (5, "y"), (2, "z")] end -end \ No newline at end of file +end From 3fa6efabc213af3ab93fe9535e83c73793669724 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Thu, 21 May 2020 16:46:12 -0300 Subject: [PATCH 07/11] Update Project.toml (#51) --- Project.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index b40860f..5fda099 100644 --- a/Project.toml +++ b/Project.toml @@ -1,12 +1,12 @@ name = "IntervalOptimisation" uuid = "c7c68f13-a4a2-5b9a-b424-07d005f8d9d2" -version = "0.4.1" +version = "0.4.2" [deps] IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253" [compat] -IntervalArithmetic = "0.15, 0.16" +IntervalArithmetic = "0.15, 0.16, 0.17" julia = "1.0" [extras] From 450607a608f33f2effb1e4194ade37ae3cf43849 Mon Sep 17 00:00:00 2001 From: Julia TagBot <50554310+JuliaTagBot@users.noreply.github.com> Date: Wed, 24 Jun 2020 20:38:00 -0500 Subject: [PATCH 08/11] Install TagBot as a GitHub Action (#50) --- .github/workflows/TagBot.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/TagBot.yml diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml new file mode 100644 index 0000000..d77d3a0 --- /dev/null +++ b/.github/workflows/TagBot.yml @@ -0,0 +1,11 @@ +name: TagBot +on: + schedule: + - cron: 0 * * * * +jobs: + TagBot: + runs-on: ubuntu-latest + steps: + - uses: JuliaRegistries/TagBot@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} From e44dad6ea3027135374e88aa3b611dda3908de55 Mon Sep 17 00:00:00 2001 From: "David P. Sanders" Date: Sun, 2 Aug 2020 09:56:25 -0400 Subject: [PATCH 09/11] Julia highlighting for code --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 37c7135..ab15ffc 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ They return an `Interval` that is guaranteed to contain the global minimum (maxi #### 1D -``` +```julia using IntervalArithmetic, IntervalOptimisation julia> @time global_min, minimisers = minimise(x -> (x^2 - 2)^2, -10..11); @@ -50,7 +50,7 @@ julia> minimisers #### 2D -``` +```julia julia> @time global_min, minimisers = minimise( X -> ( (x,y) = X; x^2 + y^2 ), (-10000..10001) × (-10000..10001) ); 0.051122 seconds (46.80 k allocations: 2.027 MiB) From 5e7b7623db93353263508e5dd31e9f6ed721f050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20K=C3=B6hler?= Date: Thu, 19 Nov 2020 22:20:37 +0100 Subject: [PATCH 10/11] Add centered forms for scalar functions --- Project.toml | 3 +++ src/IntervalOptimisation.jl | 6 ++++-- src/centered_forms.jl | 33 +++++++++++++++++++++++++++++++++ src/optimise.jl | 5 ++++- 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 src/centered_forms.jl diff --git a/Project.toml b/Project.toml index 5fda099..d59c4fc 100644 --- a/Project.toml +++ b/Project.toml @@ -3,7 +3,10 @@ uuid = "c7c68f13-a4a2-5b9a-b424-07d005f8d9d2" version = "0.4.2" [deps] +ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253" +IntervalRootFinding = "d2bf35a9-74e0-55ec-b149-d360ff49b807" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" [compat] IntervalArithmetic = "0.15, 0.16, 0.17" diff --git a/src/IntervalOptimisation.jl b/src/IntervalOptimisation.jl index 4fb2e93..aaf3570 100644 --- a/src/IntervalOptimisation.jl +++ b/src/IntervalOptimisation.jl @@ -3,6 +3,7 @@ module IntervalOptimisation export minimise, maximise, minimize, maximize export HeapedVector, SortedVector +export mean_value_form_scalar, third_order_taylor_form_scalar include("StrategyBase.jl") using .StrategyBase @@ -13,10 +14,11 @@ using .SortedVectors include("HeapedVectors.jl") using .HeapedVectors -using IntervalArithmetic +using IntervalArithmetic, IntervalRootFinding +using LinearAlgebra include("optimise.jl") - +include("centered_forms.jl") const minimize = minimise const maximize = maximise diff --git a/src/centered_forms.jl b/src/centered_forms.jl new file mode 100644 index 0000000..42278a7 --- /dev/null +++ b/src/centered_forms.jl @@ -0,0 +1,33 @@ +import ForwardDiff: gradient, jacobian, hessian + +gradient(f, X::IntervalBox) = gradient(f, X.v) +# jacobian(f, X::IntervalBox) = jacobian(f, X.v) +hessian(f, X::IntervalBox) = hessian(f, X.v) + +""" +Calculate the mean-value form of a function ``f:\\mathbb{R}^n \\to \\mathbb{R}`` +using the gradient ``\nabla f``; +this gives a second-order approximation. +""" +function mean_value_form_scalar(f, X) + m = IntervalBox(mid(X)) + + return f(m) + gradient(f, X.v) ⋅ (X - m) +end + +mean_value_form_scalar(f) = X -> mean_value_form_scalar(f, X) + + +""" +Calculate a third-order Taylor form of ``f:\\mathbb{R}^n \\to \\mathbb{R}`` using the Hessian. +""" +function third_order_taylor_form_scalar(f, X) + m = IntervalBox(mid(X)) + + H = hessian(f, X) + δ = X - m + + return f(m) + gradient(f, m) ⋅ δ + 0.5 * sum(δ[i]*H[i,j]*δ[j] for i in 1:length(X) for j in 1:length(X)) +end + +third_order_taylor_form_scalar(f) = X -> third_order_taylor_form_scalar(f, X) diff --git a/src/optimise.jl b/src/optimise.jl index 705936c..e244162 100644 --- a/src/optimise.jl +++ b/src/optimise.jl @@ -1,6 +1,9 @@ numeric_type(::Interval{T}) where {T} = T numeric_type(::IntervalBox{N, T}) where {N, T} = T +interval_mid(X::Interval) = Interval(mid(X)) +interval_mid(X::IntervalBox) = IntervalBox(mid(X)) + """ minimise(f, X, structure = SortedVector, tol=1e-3) or @@ -37,7 +40,7 @@ function minimise(f, X::T; structure = HeapedVector, tol=1e-3) where {T} end # find candidate for upper bound of global minimum by just evaluating a point in the interval: - m = sup(f(Interval.(mid.(X)))) # evaluate at midpoint of current interval + m = sup(f(interval_mid(X))) # evaluate at midpoint of current interval if m < global_min global_min = m From 3ef21e3c0e92b20ce8d0a5d240d395d25abca138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20K=C3=B6hler?= Date: Fri, 20 Nov 2020 10:07:48 +0100 Subject: [PATCH 11/11] updated CI Services from 0.7 testing to 1.5 --- .travis.yml | 3 +-- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index a6fbab2..01b2f71 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,8 @@ os: - osx julia: - - 0.7 - 1.0 + - 1.5 - nightly notifications: @@ -15,7 +15,6 @@ notifications: matrix: allow_failures: - - julia: 0.7 - julia: nightly after_success: diff --git a/appveyor.yml b/appveyor.yml index c2588f1..c799c17 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ environment: matrix: - - julia_version: 0.7 - julia_version: 1 + - julia_version: 1.5 - julia_version: nightly platform: