Skip to content

Commit

Permalink
Add UninitializedObjective functionality. (#427)
Browse files Browse the repository at this point in the history
  • Loading branch information
pkofod committed Jun 7, 2017
1 parent a9abb80 commit 6b75aae
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 5 deletions.
19 changes: 19 additions & 0 deletions src/multivariate/optimize/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ fallback_method(f, g!, h!) = Newton()

promote_objtype(method, initial_x, obj_args...) = error("No default objective type for $method and $obj_args.")
promote_objtype(method::ZerothOrderSolver, initial_x, obj_args...) = NonDifferentiable(obj_args..., initial_x)
promote_objtype(method::ZerothOrderSolver, initial_x, od::OnceDifferentiable) = od
promote_objtype(method::ZerothOrderSolver, initial_x, td::TwiceDifferentiable) = td
promote_objtype(method::ZerothOrderSolver, initial_x, nd::NonDifferentiable) = nd
promote_objtype(method::FirstOrderSolver, initial_x, obj_args...) = OnceDifferentiable(obj_args..., initial_x)
promote_objtype(method::FirstOrderSolver, initial_x, od::OnceDifferentiable) = od
promote_objtype(method::FirstOrderSolver, initial_x, td::TwiceDifferentiable) = td
promote_objtype(method::FirstOrderSolver, initial_x, f, g!, h!) = OnceDifferentiable(f, g!, initial_x)
promote_objtype(method::SecondOrderSolver, initial_x, obj_args...) = TwiceDifferentiable(obj_args..., initial_x)
promote_objtype(method::SecondOrderSolver, initial_x, td::TwiceDifferentiable) = td

# use objective.last_f_x, since this is guaranteed to be in Non-, Once-, and TwiceDifferentiable
function optimize(objective::AbstractObjective, initial_x::AbstractArray = objective.last_x_f; kwargs...)
Expand Down Expand Up @@ -77,3 +83,16 @@ function optimize{D <: Union{NonDifferentiable, OnceDifferentiable}}(d::D, initi
d = promote_objtype(method, initial_x, d)
optimize(d, initial_x, method, options)
end

initialize_objective(d::UninitializedNonDifferentiable, x) = NonDifferentiable(d, x)
initialize_objective(d::UninitializedOnceDifferentiable, x) = OnceDifferentiable(d, x)
initialize_objective(d::UninitializedTwiceDifferentiable, x) = TwiceDifferentiable(d, x)
function optimize(d::UninitializedObjective, initial_x::AbstractArray, method::Optimizer, options::Options = Options())
id = initialize_objective(d, initial_x)
id = promote_objtype(method, initial_x, id)
optimize(id, initial_x, method, options, initial_state(method, options, id, initial_x))
end
function optimize(d::UninitializedObjective, initial_x::AbstractArray)
id = initialize_objective(d, initial_x)
optimize(id)
end
45 changes: 41 additions & 4 deletions src/objective_types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,50 @@ import NLSolversBase.NonDifferentiable
import NLSolversBase.OnceDifferentiable
import NLSolversBase.TwiceDifferentiable


@compat abstract type UninitializedObjective <: AbstractObjective end
type UninitializedNonDifferentiable <: UninitializedObjective
f
end
# The user friendly/short form NonDifferentiable constructor
NonDifferentiable(f) = UninitializedNonDifferentiable(f)
NonDifferentiable(u::UninitializedNonDifferentiable, x::AbstractArray) = NonDifferentiable(u.f, x)

type UninitializedOnceDifferentiable{T} <: UninitializedObjective
f
g!
fg!::T
end
# The user friendly/short form OnceDifferentiable constructor
OnceDifferentiable(f, g!, fg!) = UninitializedOnceDifferentiable(f, g!, fg!)
OnceDifferentiable(f, g!) = UninitializedOnceDifferentiable(f, g!, nothing)
OnceDifferentiable(f) = UninitializedOnceDifferentiable(f, nothing, nothing)
OnceDifferentiable(u::UninitializedOnceDifferentiable, x::AbstractArray) = OnceDifferentiable(u.f, u.g!, u.fg!, x)
OnceDifferentiable(u::UninitializedOnceDifferentiable{Void}, x::AbstractArray) = OnceDifferentiable(u.f, u.g!, x)

type UninitializedTwiceDifferentiable{Tf, Tfg, Th} <: UninitializedObjective
f
g!::Tf
fg!::Tfg
h!::Th
end
TwiceDifferentiable(f, g!, fg!, h!) = UninitializedTwiceDifferentiable(f, g!, fg!, h!)
TwiceDifferentiable(f, g!, h!) = UninitializedTwiceDifferentiable(f, g!, nothing, h!)
TwiceDifferentiable(f, g!) = UninitializedTwiceDifferentiable(f, g!, nothing, nothing)
TwiceDifferentiable(f) = UninitializedTwiceDifferentiable(f, nothing, nothing, nothing)
TwiceDifferentiable{T<:UninitializedObjective}(u::T, x::AbstractArray) = error("Cannot construct a TwiceDifferentiable from UninitializedTwiceDifferentiable unless the gradient and Hessian is provided.")
TwiceDifferentiable(u::UninitializedTwiceDifferentiable, x::AbstractArray) = TwiceDifferentiable(u.f, u.g!, u.fg!, u.h!, x)
TwiceDifferentiable{S, T}(u::UninitializedTwiceDifferentiable{S, Void, T}, x::AbstractArray) = TwiceDifferentiable(u.f, u.g!, u.h!, x)


NonDifferentiable(f, g!, x_seed::AbstractArray) = NonDifferentiable(f, x_seed)
NonDifferentiable(f, g!, h!, x_seed::AbstractArray) = NonDifferentiable(f, x_seed)

function OnceDifferentiable{T}(d::OnceDifferentiable, x_seed::AbstractVector{T})
function OnceDifferentiable(d::OnceDifferentiable, x_seed::AbstractArray)
value_gradient!(d, x_seed)
d
end
function OnceDifferentiable{T}(f, x_seed::AbstractVector{T}; autodiff = :finite)
function OnceDifferentiable(f, x_seed::AbstractArray; autodiff = :finite)
n_x = length(x_seed)
f_calls = [1]
g_calls = [1]
Expand Down Expand Up @@ -48,7 +84,7 @@ function OnceDifferentiable{T}(f, x_seed::AbstractVector{T}; autodiff = :finite)
return OnceDifferentiable(f, g!, fg!, f(x_seed), g, copy(x_seed), copy(x_seed), f_calls, g_calls)
end

function TwiceDifferentiable{T}(f, x_seed::Vector{T}; autodiff = :finite)
function TwiceDifferentiable{T}(f, x_seed::AbstractArray{T}; autodiff = :finite)
n_x = length(x_seed)
f_calls = [1]
g_calls = [1]
Expand Down Expand Up @@ -131,7 +167,8 @@ function TwiceDifferentiable{T}(f, g!, x_seed::Array{T}; autodiff = :finite)
g, H, copy(x_seed),
copy(x_seed), copy(x_seed), f_calls, [1], [1])
end

TwiceDifferentiable(u::UninitializedTwiceDifferentiable{Void, Void, Void}, x::AbstractArray) = TwiceDifferentiable(u.f, x)
TwiceDifferentiable{T}(u::UninitializedTwiceDifferentiable{T, Void, Void}, x::AbstractArray) = TwiceDifferentiable(u.f, u.g!, x)
TwiceDifferentiable{T}(d::NonDifferentiable, x_seed::Vector{T} = d.last_x_f; autodiff = :finite) =
TwiceDifferentiable(d.f, x_seed; autodiff = autodiff)
function TwiceDifferentiable{T}(d::OnceDifferentiable, x_seed::Vector{T} = d.last_x_f; autodiff = :finite)
Expand Down
2 changes: 1 addition & 1 deletion test/multivariate/extrapolate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import LineSearches
P = precond(initial_x)
methods = [LBFGS(P=P),
ConjugateGradient(P=P),
LBFGS(extrapolate=true, linesearch = LineSearches.bt2!, P=P)]
LBFGS(extrapolate=true, linesearch = LineSearches.BackTracking(order=2), P=P)]

for (method, msg) in zip(methods, msgs)
results = Optim.optimize(f, g!, copy(initial_x), method)
Expand Down
81 changes: 81 additions & 0 deletions test/multivariate/optimize/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,84 @@
end
end
end

@testset "uninitialized interface" begin
problem = Optim.UnconstrainedProblems.examples["Exponential"]
f = problem.f
g! = problem.g!
h! = problem.h!
nd = NonDifferentiable(f)
od = OnceDifferentiable(f, g!)
td = TwiceDifferentiable(f, g!, h!)
ref = optimize(td, problem.initial_x, Newton(), Optim.Options())
# test UninitializedObjective interface
for obj in (nd, od, td)
res = []
push!(res, optimize(obj, problem.initial_x))

push!(res, optimize(obj, problem.initial_x, Optim.Options()))

push!(res, optimize(obj, problem.initial_x, Optim.Options()))
# Test passing the objective, method and option, but no inital_x
push!(res, optimize(obj, problem.initial_x, NelderMead(), Optim.Options()))
for r in res
@test norm(Optim.minimum(ref)-Optim.minimum(r)) < 1e-6
end
end
ad_res = optimize(od, problem.initial_x, Newton())
@test norm(Optim.minimum(ref)-Optim.minimum(ad_res)) < 1e-6
ad_res2 = optimize(od, problem.initial_x, Newton())
@test norm(Optim.minimum(ref)-Optim.minimum(ad_res2)) < 1e-6
# test f, g!, h! interface
for tup in ((f,), (f, g!), (f, g!, h!))
fgh_res = []
push!(fgh_res, optimize(tup..., problem.initial_x))
for m in (NelderMead(), LBFGS(), Newton())
push!(fgh_res, optimize(tup..., problem.initial_x; f_tol = 1e-8))
push!(fgh_res, optimize(tup..., problem.initial_x, m))
push!(fgh_res, optimize(tup..., problem.initial_x, m, Optim.Options()))
end
for r in fgh_res
@test norm(Optim.minimum(ref)-Optim.minimum(r)) < 1e-6
end
end
end


@testset "uninitialized objectives" begin
# Test example
function exponential(x::Vector)
return exp((2.0 - x[1])^2) + exp((3.0 - x[2])^2)
end

function exponential_gradient!(storage::Vector, x::Vector)
storage[1] = -2.0 * (2.0 - x[1]) * exp((2.0 - x[1])^2)
storage[2] = -2.0 * (3.0 - x[2]) * exp((3.0 - x[2])^2)
end
function exponential_fg!(storage, x)
exponential_gradient!(storage, x)
exponential(x)
end
function exponential_hessian!(storage::Matrix, x::Vector)
storage[1, 1] = 2.0 * exp((2.0 - x[1])^2) * (2.0 * x[1]^2 - 8.0 * x[1] + 9)
storage[1, 2] = 0.0
storage[2, 1] = 0.0
storage[2, 2] = 2.0 * exp((3.0 - x[1])^2) * (2.0 * x[2]^2 - 12.0 * x[2] + 19)
end

x_seed = [0.0, 0.0]
f_x_seed = 8157.682077608529

und = NonDifferentiable(exponential)
uod1 = OnceDifferentiable(exponential, exponential_gradient!)
uod2 = OnceDifferentiable(exponential, exponential_gradient!, exponential_fg!)
utd1 = TwiceDifferentiable(exponential, exponential_gradient!)
utd2 = TwiceDifferentiable(exponential, exponential_gradient!, exponential_hessian!)
utd3 = TwiceDifferentiable(exponential, exponential_gradient!, exponential_fg!, exponential_hessian!)
nd = NonDifferentiable(und, x_seed)
od1 = OnceDifferentiable(uod1, x_seed)
od2 = OnceDifferentiable(uod2, x_seed)
td1 = TwiceDifferentiable(utd1, x_seed)
td2 = TwiceDifferentiable(utd2, x_seed)
td3 = TwiceDifferentiable(utd3, x_seed)
end

2 comments on commit 6b75aae

@chriselrod
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the parametric typing of OnceDifferentiable breaks line 66:

gr_res = DiffBase.DiffResult(zero(T), out)

@pkofod
Copy link
Member Author

@pkofod pkofod commented on 6b75aae Jun 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

6b75aae#diff-ab516b956239be1e33f110faaa3a8b4cR48

this right? Odd it wasn't caught by a test...

Please sign in to comment.