Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deleting loop calls of Invokelatest #53

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
134 changes: 113 additions & 21 deletions src/CharibdeOptim.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
module CharibdeOptim

export constraint, charibde_min, charibde_max, ibc_maximise, diffevol_maximise
export ibc_minimise, diffevol_minimise
export minimise_by_charibde, maximise_by_charibde
export minimise_by_ibc, minimise_by_diffevol, maximise_by_ibc, maximise_by_diffevol
export constraint, OptimisationProblem, ConstrainedOptimisationProblem

using IntervalArithmetic
using Distributed
Expand All @@ -15,11 +16,99 @@ using MacroTools
import Base: invokelatest, push!
import ForwardDiff: gradient

struct OptimisationProblem{N, T}
f::Function
X::IntervalBox{N, T}
end


struct Constraint{T}
bound::Interval{T}
C::Contractor
end

struct ConstrainedOptimisationProblem{N, T}
f::Function
X::IntervalBox{N, T}
constraints::Vector{Constraint{T}}
end
"""Usage:
```
For Unconstrained Optimsation:
f = X->((x,y)=X;x^3 + 2y + 5)
A = IntervalBox(2..4, 2..3)
prob = OptimisationProblem(f, A)

(global_min, minimisers, info) = minimise_by_ibc(prob)
(global_max, maximisers, info) = maximise_by_ibc(prob)
(global_min, minimisers) = minimise_by_diffevol(prob)
(global_max, maximisers) = maximiser_by_diffevol(prob)

For Constrained Optimisation:
f = X->((x,y)=X;-(x-4)^2-(y-4)^2)
A = IntervalBox(-4..4, -4..4)

vars = ModelingToolkit.@variables x y
C1 = Constraint(vars, x+y, -Inf..4)
C2 = Constraint(vars, x+3y, -Inf..9)

prob = ConstrainedOptimisation(f, A, [C1, C2])

(global_min, minimisers, info) = minimise_by_ibc(prob)
(global_max, maximisers, info) = maximise_by_diffevol(prob)
(global_min, minimisers) = minimise_by_diffevol(prob)
(global_max, maximisers) = maximiser_by_diffevol(prob)

minimise_by_ibc/maximise_by_ibc, minimise_by_diffevol/maximise_by_diffevol find the global minimum/maximum value of the function in given search space by using Interval Bound & Contract(IBC) and Differential Evolution algorithm
```
"""
function minimise_by_ibc(prob::OptimisationProblem{N, T}; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, T}}(0)),
diffevol_chnl = RemoteChannel(()->Channel{Tuple{SVector{N, T}, T, Union{Nothing, IntervalBox{N, T}}}}(0)), structure = SortedVector, debug = false, tol=1e-6, ibc_ind = true) where{N, T}

vars = [Variable(Symbol("x",i))() for i in 1:length(prob.X)]
g(x...) = prob.f(x)
C = BasicContractor(vars, g)
invokelatest(ibc_minimise, prob.f, prob.X, C, ibc_chnl = ibc_chnl, diffevol_chnl = diffevol_chnl, structure = structure, debug = debug, tol=tol, ibc_ind = ibc_ind)
end

function maximise_by_ibc(prob::OptimisationProblem{N, T}; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, T}}(0)),
diffevol_chnl = RemoteChannel(()->Channel{Tuple{SVector{N, T}, T, Union{Nothing, IntervalBox{N, T}}}}(0)), structure = SortedVector, debug = false, tol=1e-6, ibc_ind = true) where{N, T}
vars = [Variable(Symbol("x",i))() for i in 1:length(prob.X)]
g(x...) = prob.f(x)
C = BasicContractor(vars, g)
invokelatest(ibc_maximise, prob.f, prob.X, C, ibc_chnl = ibc_chnl, diffevol_chnl = diffevol_chnl, structure = structure, debug = debug, tol=tol, ibc_ind = ibc_ind)
end

function minimise_by_ibc(prob::ConstrainedOptimisationProblem{N, T}; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, T}}(0)),
diffevol_chnl = RemoteChannel(()->Channel{Tuple{SVector{N, T}, T, Union{Nothing, IntervalBox{N, T}}}}(0)), structure = SortedVector, debug = false, tol=1e-6, ibc_ind = true) where{N, T}
vars = [Variable(Symbol("x",i))() for i in 1:length(prob.X)]
g(x...) = prob.f(x)
C = BasicContractor(vars, g)
invokelatest(ibc_minimise, prob.f, prob.X, prob.constraints, C, ibc_chnl = ibc_chnl, diffevol_chnl = diffevol_chnl, structure = structure, debug = debug, tol=tol, ibc_ind = ibc_ind)
end

function maximise_by_ibc(prob::ConstrainedOptimisationProblem{N, T}; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, T}}(0)),
diffevol_chnl = RemoteChannel(()->Channel{Tuple{SVector{N, T}, T, Union{Nothing, IntervalBox{N, T}}}}(0)), structure = SortedVector, debug = false, tol=1e-6, ibc_ind = true) where{N, T}
vars = [Variable(Symbol("x",i))() for i in 1:length(prob.X)]
g(x...) = prob.f(x)
C = BasicContractor(vars, g)
invokelatest(ibc_maximise, prob.f, prob.X, prob.constraints, C, ibc_chnl = ibc_chnl, diffevol_chnl = diffevol_chnl, structure = structure, debug = debug, tol=tol, ibc_ind = ibc_ind)
end


minimise_by_diffevol(prob::OptimisationProblem{N, T}; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, Float64}}(0)),
diffevol_chnl = RemoteChannel(()->Channel{Tuple{SVector{N, T}, T, Union{Nothing, IntervalBox{N, T}}}}(0)), np = 10*N, debug = false, de_ind = true, iterations = 20) where{N, T} = diffevol_minimise(prob.f, prob.X, ibc_chnl = ibc_chnl, diffevol_chnl = diffevol_chnl, np = np, debug = debug, de_ind = de_ind, iterations = iterations)

maximise_by_diffevol(prob::OptimisationProblem{N, T}; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, Float64}}(0)),
diffevol_chnl = RemoteChannel(()->Channel{Tuple{SVector{N, T}, T, Union{Nothing, IntervalBox{N, T}}}}(0)), np = 10*N, debug = false, de_ind = true, iterations = 20) where{N, T} = diffevol_maximise(prob.f, prob.X, ibc_chnl = ibc_chnl, diffevol_chnl = diffevol_chnl, np = np, debug = debug, de_ind = de_ind, iterations = iterations)

minimise_by_diffevol(prob::ConstrainedOptimisationProblem{N, T}; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, Float64}}(0)),
diffevol_chnl = RemoteChannel(()->Channel{Tuple{SVector{N, T}, T, Union{Nothing, IntervalBox{N, T}}}}(0)), np = 10*N, debug = false, de_ind = true, iterations = 20) where{N, T} = diffevol_minimise(prob.f, prob.X, prob.constraints, ibc_chnl = ibc_chnl, diffevol_chnl = diffevol_chnl, np = np, debug = debug, de_ind = de_ind, iterations = iterations)

maximise_by_diffevol(prob::ConstrainedOptimisationProblem{N, T}; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, Float64}}(0)),
diffevol_chnl = RemoteChannel(()->Channel{Tuple{SVector{N, T}, T, Union{Nothing, IntervalBox{N, T}}}}(0)), np = 10*N, debug = false, de_ind = true, iterations = 20) where{N, T} = diffevol_maximise(prob.f, prob.X, prob.constraints, ibc_chnl = ibc_chnl, diffevol_chnl = diffevol_chnl, np = np, debug = debug, de_ind = de_ind, iterations = iterations)


function constraint(vars, constraint_expr::Operation, bound::Interval{T}; epsilon = 1e-4) where{T}
C = Contractor(vars, constraint_expr)
if diam(bound) == 0.0
Expand Down Expand Up @@ -56,66 +145,69 @@ end
```
f = X->((x,y)=X;x^3 + 2y + 5)
A = IntervalBox(2..4, 2..3)
(global_min, minimisers, info) = charibde_min(f, A)
(global_max, maximisers, info) = charibde_max(f, A)
prob = OptimisationProblem(f, A)
(global_min, minimisers, info) = minimise_by_charibde(prob)
(global_max, maximisers, info) = maximise_by_charibde(prob)

charibde_min/charibde_max find the global minimum/maximum value of the function in given search space by using two algorithms Interval Bound & Contract(IBC) and Differential Evolution inparallel
TODO: Fix the parallel implementation of charibde_min/max for Constrained Optimisation
```
"""
function charibde_min(f::Function, X::IntervalBox{N,T}; workers = 2, tol = 1e-6, np = N*10, debug = false) where{N,T}
function minimise_by_charibde(prob::OptimisationProblem{N, T}; workers = 2, tol = 1e-6, np = N*10, debug = false) where{N,T}

worker_ids = Distributed.workers()
if workers > 1
if worker_ids[1] == 1
error("Not enough workers available: Add one worker and load the package on it")
end

(chnl1, chnl2) = create_channels(X, workers) #IBC recieve element from chnl1 and DiffEvolution from chnl2
(chnl1, chnl2) = create_channels(prob.X, workers) #IBC recieve element from chnl1 and DiffEvolution from chnl2

r1 = remotecall(diffevol_minimise, worker_ids[1], f, X, chnl1, chnl2, np = np, de_ind = false)
r2 = remotecall(ibc_minimise, worker_ids[2], f, X, ibc_chnl = chnl1, diffevol_chnl = chnl2, tol = tol, debug = debug, ibc_ind = false)
r1 = remotecall(minimise_by_diffevol, worker_ids[1], prob, chnl1, chnl2, np = np, de_ind = false)
r2 = remotecall(minimise_by_ibc, worker_ids[2], prob, ibc_chnl = chnl1, diffevol_chnl = chnl2, tol = tol, debug = debug, ibc_ind = false)
return fetch(r2)
else
(chnl1, chnl2) = create_channels(X, workers)
(chnl1, chnl2) = create_channels(prob.X, workers)

r1 = @async diffevol_minimise(f, X, chnl1, chnl2, np = np, de_ind = false)
r2 = @async ibc_minimise(f, X, ibc_chnl = chnl1, diffevol_chnl = chnl2, tol = tol, debug = debug, ibc_ind = false)
r1 = @async minimise_by_diffevol(prob, chnl1, chnl2, np = np, de_ind = false)
r2 = @async minimise_by_ibc(prob, ibc_chnl = chnl1, diffevol_chnl = chnl2, tol = tol, debug = debug, ibc_ind = false)
return fetch(r2)
end
end


function charibde_min(f::Function, X::IntervalBox{N,T}, constraints::Vector{Constraint{T}}; workers = 2, tol = 1e-6, np = N*10, debug = false) where{N,T}
function minimise_by_charibde(prob::ConstrainedOptimisationProblem{N, T}; workers = 2, tol = 1e-6, np = N*10, debug = false) where{N,T}

worker_ids = Distributed.workers()
if workers > 1
if nprocs() < 3
error("Not enough workers available: Session should have atleast 2 workers more")
end

(chnl1, chnl2) = create_channels(X, workers)
(chnl1, chnl2) = create_channels(prob.X, workers)

r1 = remotecall(diffevol_minimise, worker_ids[1], f, X, constraints, ibc_chnl = chnl1, diffevol_chnl = chnl2, np = np, de_ind = false)
r2 = remotecall(ibc_minimise, worker_ids[2], f, X, constraints, ibc_chnl = chnl1, diffevol_chnl = chnl2, tol = tol, debug = debug, ibc_ind = false)
r1 = remotecall(minimise_by_diffevol, worker_ids[1], prob, ibc_chnl = chnl1, diffevol_chnl = chnl2, np = np, de_ind = false)
r2 = remotecall(minimise_by_ibc, worker_ids[2], prob, ibc_chnl = chnl1, diffevol_chnl = chnl2, tol = tol, debug = debug, ibc_ind = false)
return fetch(r2)
else
(chnl1, chnl2) = create_channels(X, workers)

r1 = @async diffevol_minimise(f, X, constraints, ibc_chnl = chnl1, diffevol_chnl = chnl2, np = np, de_ind = false)
r2 = @async ibc_minimise(f, X, constraints, ibc_chnl = chnl1, diffevol_chnl = chnl2, tol= tol, debug = debug, ibc_ind = false)
r1 = @async minimise_by_diffevol(prob, ibc_chnl = chnl1, diffevol_chnl = chnl2, np = np, de_ind = false)
r2 = @async minimise_by_ibc(prob, ibc_chnl = chnl1, diffevol_chnl = chnl2, tol= tol, debug = debug, ibc_ind = false)
return fetch(r2)
end
end


function charibde_max(f::Function, X::IntervalBox{N,T}; workers = 2, tol = 1e-6, np = N*10, debug = false) where{N,T}
bound, minimizers, info = charibde_min(x -> -f(x), X, workers = workers, tol = tol, np = np, debug = debug)
function maximise_by_charibde(prob::OptimisationProblem{N, T}; workers = 2, tol = 1e-6, np = N*10, debug = false) where{N,T}
new_prob = OptimisationProblem(x -> -prob.f(x), prob.X)
bound, minimizers, info = minimise_by_charibde(new_prob, workers = workers, tol = tol, np = np, debug = debug)
return -bound, minimizers, info
end

function charibde_max(f::Function, X::IntervalBox{N,T}, constraints::Vector{Constraint{T}}; workers = 2, tol = 1e-6, np = N*10, debug = false) where{N,T}
bound, minimizers, info = charibde_min(x -> -f(x), X, constraints, workers = workers, tol = tol, np = np, debug = debug)
function maximise_by_charibde(prob::ConstrainedOptimisationProblem{N, T}; workers = 2, tol = 1e-6, np = N*10, debug = false) where{N,T}
new_prob = ConstrainedOptimisationProblem(x-> -prob.f(x), prob.X, prob.constraints)
bound, minimizers, info = minimise_by_charibde(new_prob, workers = workers, tol = tol, np = np, debug = debug)
return -bound, minimizers, info
end

Expand Down
4 changes: 2 additions & 2 deletions src/ConstrainedDifferentialEvolution.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ function diffevol_minimise(f::Function, X::IntervalBox{N, T}, constraints::Vecto
(c1, c2) = (0, 0)

for constraint in constraints
if invokelatest(constraint.C, m) ∈ constraint.bound
if constraint.C(m) ∈ constraint.bound
c1 = c1 + 1
end
if invokelatest(constraint.C, pop[i]) ∈ constraint.bound
if constraint.C(pop[i]) ∈ constraint.bound
c2 = c2 + 1
end
end
Expand Down
17 changes: 7 additions & 10 deletions src/ConstrainedIBC.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ function hc4(X::IntervalBox{N,T}, constraints::Vector{Constraint{T}}, tol=1e-5)
while true
X_temp = X
for i in 1:n
X = invokelatest(constraints[i].C, constraints[i].bound, X)
X = constraints[i].C(constraints[i].bound, X)
end
if isempty(X) || sum(dist.(X, X_temp)) < tol
break
Expand All @@ -25,7 +25,7 @@ function contraction(f::Function, C, global_min::Float64, X::IntervalBox{N,T}, c
lb = -Inf
while true
X_temp = X
X = invokelatest(C, -Inf..global_min, X)
X = C(-Inf..global_min, X)
lb = inf(f(X))
constraints, X = hc4(X, constraints)

Expand All @@ -41,7 +41,7 @@ function generate_random_feasible_point(X::IntervalBox{N, T}, constraints::Vecto
for i in 1:30
point = [X[j].lo + (1-rand())*(X[j].hi - X[j].lo) for j in 1:length(X)] # discover a random point in interval box X
for j in 1:length(constraints)
if !(invokelatest(constraints[j].C, point) ⊆ constraints[j].bound)
if !(constraints[j].C(point) ⊆ constraints[j].bound)
break
end
if j == length(constraints)
Expand Down Expand Up @@ -80,19 +80,16 @@ end

function check_feasiblity(point::SVector{N,T}, constraints::Vector{Constraint{T}}) where{N, T}
for constraint in constraints
if !(invokelatest(constraint.C, point) ∈ constraint.bound)
if !(constraint.C(point) ∈ constraint.bound)
return false
end
end
return true
end

function ibc_minimise(f::Function , X::IntervalBox{N,T}, constraints::Vector{Constraint{T}}; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, T}}(0)),
function ibc_minimise(f::Function , X::IntervalBox{N,T}, constraints::Vector{Constraint{T}}, C::BasicContractor; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, T}}(0)),
diffevol_chnl = RemoteChannel(()->Channel{Tuple{SVector{N, T}, T, Union{Nothing, IntervalBox{N, T}}}}(0)), structure = SortedVector, debug = false, tol=1e-6, ibc_ind = true) where{N, T}

vars = [Variable(Symbol(:(x[$i])))() for i in 1:N]
g(x...) = f(x)
C = BasicContractor(vars, g)

working = structure([(X, inf(f(X)))], x->x[2]) # list of boxes with corresponding lower bound, arranged according to selected structure :
minimizers = IntervalBox{N,T}[]
Expand Down Expand Up @@ -216,8 +213,8 @@ function ibc_minimise(f::Function , X::IntervalBox{N,T}, constraints::Vector{Con
end


function ibc_maximise(f::Function , X::IntervalBox{N,T}, constraints::Vector{Constraint{T}}; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, T}}(0)),
function ibc_maximise(f::Function , X::IntervalBox{N,T}, constraints::Vector{Constraint{T}}, C::BasicContractor; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, T}}(0)),
diffevol_chnl = RemoteChannel(()->Channel{Tuple{SVector{N, T}, T, Union{Nothing, IntervalBox{N, T}}}}(0)), structure = SortedVector, debug = false, tol=1e-6, ibc_ind = true) where{N, T}
bound, minimizer, info = ibc_minimise(x -> -f(x), X, constraints, ibc_chnl = ibc_chnl, diffevol_chnl = diffevol_chnl, debug = debug, tol = tol, ibc_ind = ibc_ind)
bound, minimizer, info = ibc_minimise(x -> -f(x), X, constraints, C, ibc_chnl = ibc_chnl, diffevol_chnl = diffevol_chnl, debug = debug, tol = tol, ibc_ind = ibc_ind)
return -bound, minimizer, info
end
36 changes: 7 additions & 29 deletions src/IBC.jl
Original file line number Diff line number Diff line change
@@ -1,31 +1,8 @@
"""Usage:
```
For Unconstrained Optimsation:
f = X->((x,y)=X;x^3 + 2y + 5)
A = IntervalBox(2..4, 2..3)
(global_min, minimisers, info) = ibc_minimise(f, A)
(global_max, maximisers, info) = ibc_maximise(f, A)

For Constrained Optimisation:
f = X->((x,y)=X;-(x-4)^2-(y-4)^2)
A = IntervalBox(-4..4, -4..4)

vars = ModelingToolkit.@variables x y
C1 = Constraint(vars, x+y, -Inf..4)
C2 = Constraint(vars, x+3y, -Inf..9)

(global_min, minimisers, info) = ibc_minimise(f, A, [C1, C2])
(global_max, maximisers, info) = ibc_maximise(f, A, [C1, C2])

ibc_minimise/ibc_maximise find the global minimum/maximum value of the function in given search space by using Interval Bound & Contract(IBC) algorithm
```
"""
function ibc_minimise(f::Function , X::IntervalBox{N,T}; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, T}}(0)),

function ibc_minimise(f::Function , X::IntervalBox{N,T}, C::BasicContractor; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, T}}(0)),
diffevol_chnl = RemoteChannel(()->Channel{Tuple{SVector{N, T}, T, Union{Nothing, IntervalBox{N, T}}}}(0)), debug = false, structure = SortedVector, tol=1e-6, ibc_ind = true) where{N, T}

vars = [Variable(Symbol("x",i))() for i in 1:length(X)]
g(x...) = f(x)
C = BasicContractor(vars, g)



working = structure([(X, inf(f(X)))], x->x[2]) # list of boxes with corresponding lower bound, arranged according to selected structure :
Expand Down Expand Up @@ -71,7 +48,8 @@ function ibc_minimise(f::Function , X::IntervalBox{N,T}; ibc_chnl = RemoteChanne
end

A = -∞..global_min
X = invokelatest(C, A, X) # Contracting the box by constraint f(X) < globla_min
#X = invokelatest(C, A, X) # Contracting the box by constraint f(X) < globla_min
X = C(A, X)
X_min = inf(f(X))

if debug
Expand Down Expand Up @@ -140,8 +118,8 @@ function ibc_minimise(f::Function , X::IntervalBox{N,T}; ibc_chnl = RemoteChanne

end

function ibc_maximise(f::Function , X::IntervalBox{N,T}; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, T}}(0)),
function ibc_maximise(f::Function , X::IntervalBox{N,T}, C::BasicContractor; ibc_chnl = RemoteChannel(()->Channel{Tuple{IntervalBox{N,T}, T}}(0)),
diffevol_chnl = RemoteChannel(()->Channel{Tuple{SVector{N, T}, T, Union{Nothing, IntervalBox{N, T}}}}(0)), debug = false, structure = SortedVector, tol=1e-6, ibc_ind = true) where{N, T}
bound, minimizer, info = ibc_minimise(x -> -f(x), X, ibc_chnl = ibc_chnl, diffevol_chnl = diffevol_chnl, debug = debug, structure = structure, tol = tol, ibc_ind = true)
bound, minimizer, info = ibc_minimise(x -> -f(x), X, C, ibc_chnl = ibc_chnl, diffevol_chnl = diffevol_chnl, debug = debug, structure = structure, tol = tol, ibc_ind = true)
return -bound, minimizer, info
end
Loading