Skip to content

Commit b3ef811

Browse files
committed
Incorporate changes from review comments
1 parent ae55541 commit b3ef811

File tree

3 files changed

+70
-120
lines changed

3 files changed

+70
-120
lines changed

REQUIRE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ julia 0.5
22

33
IntervalArithmetic 0.9.1
44
IntervalRootFinding 0.1
5+
IntervalConstraintProgramming
6+
DataStructures

examples/optimise1.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ using IntervalOptimisation, IntervalArithmetic, IntervalConstraintProgramming
22

33

44
# Unconstrained Optimisation
5+
# Example from Eldon Hansen - Global Optimisation using Interval Analysis, Chapter 11
56
f(x, y) = (1.5 - x * (1 - y))^2 + (2.25 - x * (1 - y^2))^2 + (2.625 - x * (1 - y^3))^2
67
# f (generic function with 2 methods)
78

@@ -29,6 +30,7 @@ minimise_icp(f, X)
2930

3031

3132
# Constrained Optimisation
33+
# Example 1 from http://archimedes.cheme.cmu.edu/?q=baronexamples
3234
f(X) = -1 * (X[1] + X[2])
3335
# f (generic function with 1 method)
3436

src/optimise1.jl

Lines changed: 66 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,48 @@
1-
using IntervalRootFinding, IntervalArithmetic, StaticArrays, ForwardDiff, BenchmarkTools, Compat, IntervalOptimisation, DataStructures, IntervalConstraintProgramming
2-
3-
import Base.isless
4-
5-
struct IntervalMinima{T<:Real}
6-
intval::Interval{T}
7-
global_minimum::T
1+
struct IntervalMinimum{T<:Real}
2+
interval::Interval{T}
3+
minimum::T
84
end
95

10-
function isless(a::IntervalMinima{T}, b::IntervalMinima{T}) where {T<:Real}
11-
return isless(a.global_minimum, b.global_minimum)
12-
end
6+
Base.isless(a::IntervalMinimum{T}, b::IntervalMinimum{T}) where {T<:Real} = isless(a.minimum, b.minimum)
137

14-
function minimise1d(f::Function, x::Interval{T}; reltol=1e-3, abstol=1e-3) where {T<:Real}
8+
function minimise1d(f::Function, x::Interval{T}; reltol=1e-3, abstol=1e-3, use_deriv=false, use_second_deriv=false) where {T<:Real}
159

16-
Q = binary_minheap(IntervalMinima{T})
10+
Q = binary_minheap(IntervalMinimum{T})
1711

1812
global_minimum = f(interval(mid(x))).hi
1913

2014
arg_minima = Interval{T}[]
2115

22-
push!(Q, IntervalMinima(x, global_minimum))
16+
push!(Q, IntervalMinimum(x, global_minimum))
2317

2418
while !isempty(Q)
2519

2620
p = pop!(Q)
2721

28-
if isempty(p.intval)
29-
continue
30-
end
31-
32-
if p.global_minimum > global_minimum
22+
if isempty(p.interval)
3323
continue
3424
end
3525

36-
current_minimum = f(interval(mid(p.intval))).hi
37-
38-
if current_minimum < global_minimum
39-
global_minimum = current_minimum
40-
end
41-
42-
if diam(p.intval) < abstol
43-
push!(arg_minima, p.intval)
44-
else
45-
x1, x2 = bisect(p.intval)
46-
push!(Q, IntervalMinima(x1, f(x1).lo), IntervalMinima(x2, f(x2).lo))
47-
end
48-
end
49-
lb = minimum(inf.(f.(arg_minima)))
50-
51-
return lb..global_minimum, arg_minima
52-
end
53-
54-
function minimise1d_deriv(f::Function, x::Interval{T}; reltol=1e-3, abstol=1e-3) where {T<:Real}
55-
56-
Q = binary_minheap(IntervalMinima{T})
57-
58-
global_minimum = f(interval(mid(x))).hi
59-
60-
arg_minima = Interval{T}[]
61-
62-
push!(Q, IntervalMinima(x, global_minimum))
63-
64-
while !isempty(Q)
65-
66-
p = pop!(Q)
67-
68-
if isempty(p.intval)
26+
if p.minimum > global_minimum
6927
continue
7028
end
7129

72-
if p.global_minimum > global_minimum
73-
continue
30+
if use_deriv
31+
deriv = ForwardDiff.derivative(f, p.interval)
32+
if 0 deriv
33+
continue
34+
end
7435
end
7536

76-
deriv = ForwardDiff.derivative(f, p.intval)
77-
if 0 deriv
78-
continue
79-
end
8037
# Second derivative contractor
81-
# doublederiv = ForwardDiff.derivative(x->ForwardDiff.derivative(f, x), p.intval)
82-
# if doublederiv < 0
83-
# continue
84-
# end
85-
86-
m = mid(p.intval)
38+
if use_second_deriv
39+
doublederiv = ForwardDiff.derivative(x->ForwardDiff.derivative(f, x), p.interval)
40+
if doublederiv < 0
41+
continue
42+
end
43+
end
8744

45+
m = mid(p.interval)
8846
current_minimum = f(interval(m)).hi
8947

9048
if current_minimum < global_minimum
@@ -93,33 +51,24 @@ function minimise1d_deriv(f::Function, x::Interval{T}; reltol=1e-3, abstol=1e-3)
9351

9452

9553
# Contractor 1
96-
x = m .+ extended_div((interval(-∞, global_minimum) - f(m)), deriv)
97-
98-
x = x .∩ p.intval
54+
if use_deriv
55+
x = m .+ extended_div((interval(-∞, global_minimum) - f(m)), deriv)
9956

100-
# # Contractor 2 (Second derivative, expanding more on the Taylor Series, not beneficial in practice)
101-
# x = m .+ quadratic_roots(doublederiv/2, ForwardDiff.derivative(f, interval(m)), f(m) - interval(-∞, global_minimum))
102-
#
103-
# x = x .∩ p.intval
57+
x = x .∩ p.interval
58+
end
10459

105-
if diam(p.intval) < abstol
106-
push!(arg_minima, p.intval)
60+
if diam(p.interval) < abstol
61+
push!(arg_minima, p.interval)
10762
else
108-
if isempty(x[2])
63+
64+
if use_deriv && isempty(x[2])
10965
x1, x2 = bisect(x[1])
110-
push!(Q, IntervalMinima(x1, f(x1).lo), IntervalMinima(x2, f(x2).lo))
111-
else
112-
push!(Q, IntervalMinima.(x, inf.(f.(x)))...)
66+
push!(Q, IntervalMinimum(x1, f(x1).lo), IntervalMinimum(x2, f(x2).lo))
67+
continue
11368
end
11469

115-
# Second Deriv contractor
116-
# if isempty(x[2])
117-
# x1, x2 = bisect(x[1])
118-
# push!(Q, IntervalMinima(x1, f(x1).lo), IntervalMinima(x2, f(x2).lo))
119-
# else
120-
# x1, x2, x3 = x
121-
# push!(Q, IntervalMinima(x1, f(x1).lo), IntervalMinima(x2, f(x2).lo), IntervalMinima(x3, f(x3).lo))
122-
# end
70+
x1, x2 = bisect(p.interval)
71+
push!(Q, IntervalMinimum(x1, f(x1).lo), IntervalMinimum(x2, f(x2).lo))
12372
end
12473
end
12574
lb = minimum(inf.(f.(arg_minima)))
@@ -128,63 +77,62 @@ function minimise1d_deriv(f::Function, x::Interval{T}; reltol=1e-3, abstol=1e-3)
12877
end
12978

13079

131-
132-
133-
struct IntervalBoxMinima{N, T<:Real}
134-
intval::IntervalBox{N, T}
135-
global_minimum::T
80+
struct IntervalBoxMinimum{N, T<:Real}
81+
interval::IntervalBox{N, T}
82+
minimum::T
13683
end
13784

138-
struct constraint{T<:Real}
139-
f::Function
85+
"""
86+
Datatype to provide constraints to Global Optimisation such as:
87+
```
88+
Constraint(x->(x^2 - 10), -∞..1)
89+
```
90+
"""
91+
struct Constraint{F, T<:Real}
92+
f::F
14093
c::Interval{T}
14194
end
14295

143-
function isless(a::IntervalBoxMinima{N, T}, b::IntervalBoxMinima{N, T}) where {N, T<:Real}
144-
return isless(a.global_minimum, b.global_minimum)
145-
end
96+
Base.isless(a::IntervalBoxMinimum{N, T}, b::IntervalBoxMinimum{N, T}) where {N, T<:Real} = isless(a.minimum, b.minimum)
14697

14798
function minimise_icp(f::Function, x::IntervalBox{N, T}; reltol=1e-3, abstol=1e-3) where {N, T<:Real}
14899

149-
Q = binary_minheap(IntervalBoxMinima{N, T})
100+
Q = binary_minheap(IntervalBoxMinimum{N, T})
150101

151102
global_minimum =
152103

153104
x = icp(f, x, -..global_minimum)
154105

155106
arg_minima = IntervalBox{N, T}[]
156107

157-
push!(Q, IntervalBoxMinima(x, global_minimum))
108+
push!(Q, IntervalBoxMinimum(x, global_minimum))
158109

159110
while !isempty(Q)
160111

161112
p = pop!(Q)
162113

163-
if isempty(p.intval)
114+
if isempty(p.interval)
164115
continue
165116
end
166117

167-
if p.global_minimum > global_minimum
118+
if p.minimum > global_minimum
168119
continue
169120
end
170121

171-
current_minimum = f(interval.(mid(p.intval))).hi
122+
current_minimum = f(interval.(mid(p.interval))).hi
172123

173124
if current_minimum < global_minimum
174125
global_minimum = current_minimum
175126
end
176-
# if all(0 .∉ ForwardDiff.gradient(f, p.intval.v))
177-
# continue
178-
# end
179127

180-
X = icp(f, p.intval, -..global_minimum)
128+
X = icp(f, p.interval, -..global_minimum)
181129

182-
if diam(p.intval) < abstol
183-
push!(arg_minima, p.intval)
130+
if diam(p.interval) < abstol
131+
push!(arg_minima, p.interval)
184132

185133
else
186134
x1, x2 = bisect(X)
187-
push!(Q, IntervalBoxMinima(x1, f(x1).lo), IntervalBoxMinima(x2, f(x2).lo))
135+
push!(Q, IntervalBoxMinimum(x1, f(x1).lo), IntervalBoxMinimum(x2, f(x2).lo))
188136
end
189137
end
190138

@@ -193,9 +141,9 @@ function minimise_icp(f::Function, x::IntervalBox{N, T}; reltol=1e-3, abstol=1e-
193141
return lb..global_minimum, arg_minima
194142
end
195143

196-
function minimise_icp_constrained(f::Function, x::IntervalBox{N, T}, constraints::Vector{constraint{T}} = Vector{constraint{T}}(); reltol=1e-3, abstol=1e-3) where {N, T<:Real}
144+
function minimise_icp_constrained(f::Function, x::IntervalBox{N, T}, constraints::Vector{Constraint{T}} = Vector{Constraint{T}}(); reltol=1e-3, abstol=1e-3) where {N, T<:Real}
197145

198-
Q = binary_minheap(IntervalBoxMinima{N, T})
146+
Q = binary_minheap(IntervalBoxMinimum{N, T})
199147

200148
global_minimum =
201149

@@ -207,40 +155,38 @@ function minimise_icp_constrained(f::Function, x::IntervalBox{N, T}, constraints
207155

208156
arg_minima = IntervalBox{N, T}[]
209157

210-
push!(Q, IntervalBoxMinima(x, global_minimum))
158+
push!(Q, IntervalBoxMinimum(x, global_minimum))
211159

212160
while !isempty(Q)
213161

214162
p = pop!(Q)
215163

216-
if isempty(p.intval)
164+
if isempty(p.interval)
217165
continue
218166
end
219167

220-
if p.global_minimum > global_minimum
168+
if p.minimum > global_minimum
221169
continue
222170
end
223171

224-
# current_minimum = f(interval.(mid(p.intval))).hi
225-
current_minimum = f(p.intval).hi
172+
# current_minimum = f(interval.(mid(p.interval))).hi
173+
current_minimum = f(p.interval).hi
226174

227175
if current_minimum < global_minimum
228176
global_minimum = current_minimum
229177
end
230-
# if 0 .∉ ForwardDiff.gradient(f, p.intval.v)
231-
# continue
232-
# end
233-
X = icp(f, p.intval, -..global_minimum)
178+
179+
X = icp(f, p.interval, -..global_minimum)
234180

235181
for t in constraints
236182
X = icp(t.f, X, t.c)
237183
end
238184

239-
if diam(p.intval) < abstol
240-
push!(arg_minima, p.intval)
185+
if diam(p.interval) < abstol
186+
push!(arg_minima, p.interval)
241187
else
242188
x1, x2 = bisect(X)
243-
push!(Q, IntervalBoxMinima(x1, f(x1).lo), IntervalBoxMinima(x2, f(x2).lo))
189+
push!(Q, IntervalBoxMinimum(x1, f(x1).lo), IntervalBoxMinimum(x2, f(x2).lo))
244190
end
245191
end
246192
lb = minimum(inf.(f.(arg_minima)))

0 commit comments

Comments
 (0)