Skip to content

Commit f9a837c

Browse files
Merge pull request #599 from SciML/optprob
Add GalacticOptim-compatible OptimizationProblem generation
2 parents 9ef03df + e518215 commit f9a837c

File tree

6 files changed

+159
-19
lines changed

6 files changed

+159
-19
lines changed

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,13 @@ julia = "1.2"
5959
[extras]
6060
Dagger = "d58978e5-989f-55fb-8d15-ea34adc7bf54"
6161
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
62+
GalacticOptim = "a75be94c-b780-496d-a8a9-0878b188d577"
63+
Optim = "429524aa-4258-5aef-a3af-852621145aeb"
6264
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
6365
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
6466
SteadyStateDiffEq = "9672c7b4-1e72-59bd-8a11-6ac3964bc41f"
6567
StochasticDiffEq = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0"
6668
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
6769

6870
[targets]
69-
test = ["Dagger", "ForwardDiff", "OrdinaryDiffEq", "Random", "SteadyStateDiffEq", "Test", "StochasticDiffEq"]
71+
test = ["Dagger", "ForwardDiff", "GalacticOptim", "OrdinaryDiffEq", "Optim", "Random", "SteadyStateDiffEq", "Test", "StochasticDiffEq"]

src/systems/diffeqs/modelingtoolkitize.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,27 @@ function modelingtoolkitize(prob::DiffEqBase.SDEProblem)
8484

8585
de
8686
end
87+
88+
89+
"""
90+
$(TYPEDSIGNATURES)
91+
92+
Generate `OptimizationSystem`, dependent variables, and parameters from an `OptimizationProblem`.
93+
"""
94+
function modelingtoolkitize(prob::DiffEqBase.OptimizationProblem)
95+
96+
if prob.p isa Tuple || prob.p isa NamedTuple
97+
p = [x for x in prob.p]
98+
else
99+
p = prob.p
100+
end
101+
102+
vars = reshape([Variable(:x, i)() for i in eachindex(prob.u0)],size(prob.u0))
103+
params = p isa DiffEqBase.NullParameters ? [] :
104+
reshape([Variable(,i)() for i in eachindex(p)],size(Array(p)))
105+
106+
107+
eqs = prob.f(vars, params)
108+
de = OptimizationSystem(eqs,vec(vars),vec(params))
109+
de
110+
end

src/systems/optimization/optimizationsystem.jl

Lines changed: 80 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,12 @@ end
6363

6464
function generate_hessian(sys::OptimizationSystem, vs = states(sys), ps = parameters(sys);
6565
sparse = false, kwargs...)
66-
hes = calculate_hessian(sys)
6766
if sparse
68-
hes = sparse(hes)
67+
hess = sparsehessian(equations(sys),[dv() for dv in states(sys)])
68+
else
69+
hess = calculate_hessian(sys)
6970
end
70-
return build_function(hes, convert.(Variable,vs), convert.(Variable,ps);
71+
return build_function(hess, convert.(Variable,vs), convert.(Variable,ps);
7172
conv = AbstractSysToExpr(sys),kwargs...)
7273
end
7374

@@ -84,12 +85,18 @@ namespace_operation(sys::OptimizationSystem) = namespace_operation(sys.op,sys.na
8485
hessian_sparsity(sys::OptimizationSystem) =
8586
hessian_sparsity(sys.op,[dv() for dv in states(sys)])
8687

88+
struct AutoModelingToolkit <: DiffEqBase.AbstractADType end
89+
90+
DiffEqBase.OptimizationProblem(sys::OptimizationSystem,args...;kwargs...) =
91+
DiffEqBase.OptimizationProblem{true}(sys::OptimizationSystem,args...;kwargs...)
92+
8793
"""
8894
```julia
8995
function DiffEqBase.OptimizationProblem{iip}(sys::OptimizationSystem,
9096
parammap=DiffEqBase.NullParameters();
9197
u0=nothing, lb=nothing, ub=nothing,
92-
hes = false, sparse = false,
98+
grad = false,
99+
hess = false, sparse = false,
93100
checkbounds = false,
94101
linenumbers = true, parallel=SerialForm(),
95102
kwargs...) where iip
@@ -98,30 +105,53 @@ function DiffEqBase.OptimizationProblem{iip}(sys::OptimizationSystem,
98105
Generates an OptimizationProblem from an OptimizationSystem and allows for automatically
99106
symbolically calculating numerical enhancements.
100107
"""
101-
function DiffEqBase.OptimizationProblem{iip}(sys::OptimizationSystem,
108+
function DiffEqBase.OptimizationProblem{iip}(sys::OptimizationSystem, u0,
102109
parammap=DiffEqBase.NullParameters();
103-
u0=nothing, lb=nothing, ub=nothing,
104-
hes = false, sparse = false,
110+
lb=nothing, ub=nothing,
111+
grad = false,
112+
hess = false, sparse = false,
105113
checkbounds = false,
106114
linenumbers = true, parallel=SerialForm(),
107115
kwargs...) where iip
108116
dvs = states(sys)
109117
ps = parameters(sys)
110118

111119
f = generate_function(sys,checkbounds=checkbounds,linenumbers=linenumbers,
112-
parallel=parallel,expression=Val{false})
120+
expression=Val{false})
113121
u0 = varmap_to_vars(u0,dvs)
122+
123+
if grad
124+
grad_oop,grad_iip = generate_gradient(sys,checkbounds=checkbounds,linenumbers=linenumbers,
125+
parallel=parallel,expression=Val{false})
126+
_grad(u,p) = grad_oop(u,p)
127+
_grad(J,u,p) = (grad_iip(J,u,p); J)
128+
else
129+
_grad = nothing
130+
end
131+
132+
if hess
133+
hess_oop,hess_iip = generate_hessian(sys,checkbounds=checkbounds,linenumbers=linenumbers,
134+
sparse=sparse,parallel=parallel,expression=Val{false})
135+
_hess(u,p) = hess_oop(u,p)
136+
_hess(J,u,p) = (hess_iip(J,u,p); J)
137+
else
138+
_hess = nothing
139+
end
140+
141+
_f = DiffEqBase.OptimizationFunction{iip,AutoModelingToolkit,typeof(f),typeof(_grad),typeof(_hess),Nothing,Nothing,Nothing,Nothing}(f,AutoModelingToolkit(),_grad,_hess,nothing,nothing,nothing,nothing,0)
142+
114143
p = varmap_to_vars(parammap,ps)
115144
lb = varmap_to_vars(lb,dvs)
116145
ub = varmap_to_vars(ub,dvs)
117-
OptimizationProblem(f,p;u0=u0,lb=lb,ub=ub,kwargs...)
146+
OptimizationProblem{iip}(_f,u0,p;lb=lb,ub=ub,kwargs...)
118147
end
119148

120149
"""
121150
```julia
122151
function DiffEqBase.OptimizationProblemExpr{iip}(sys::OptimizationSystem,
123152
parammap=DiffEqBase.NullParameters();
124153
u0=nothing, lb=nothing, ub=nothing,
154+
grad = false,
125155
hes = false, sparse = false,
126156
checkbounds = false,
127157
linenumbers = true, parallel=SerialForm(),
@@ -134,18 +164,36 @@ calculating numerical enhancements.
134164
"""
135165
struct OptimizationProblemExpr{iip} end
136166

137-
function OptimizationProblemExpr{iip}(sys::OptimizationSystem,
167+
OptimizationProblemExpr(sys::OptimizationSystem,args...;kwargs...) =
168+
OptimizationProblemExpr{true}(sys::OptimizationSystem,args...;kwargs...)
169+
170+
function OptimizationProblemExpr{iip}(sys::OptimizationSystem, u0,
138171
parammap=DiffEqBase.NullParameters();
139-
u0=nothing, lb=nothing, ub=nothing,
140-
hes = false, sparse = false,
172+
lb=nothing, ub=nothing,
173+
grad = false,
174+
hess = false, sparse = false,
141175
checkbounds = false,
142176
linenumbers = false, parallel=SerialForm(),
143177
kwargs...) where iip
144178
dvs = states(sys)
145179
ps = parameters(sys)
146-
180+
idx = iip ? 2 : 1
147181
f = generate_function(sys,checkbounds=checkbounds,linenumbers=linenumbers,
148-
parallel=parallel,expression=Val{true})
182+
expression=Val{true})
183+
if grad
184+
_grad = generate_gradient(sys,checkbounds=checkbounds,linenumbers=linenumbers,
185+
parallel=parallel,expression=Val{false})[idx]
186+
else
187+
_grad = :nothing
188+
end
189+
190+
if hess
191+
_hess = generate_hessian(sys,checkbounds=checkbounds,linenumbers=linenumbers,
192+
sparse=sparse,parallel=parallel,expression=Val{false})[idx]
193+
else
194+
_hess = :nothing
195+
end
196+
149197
u0 = varmap_to_vars(u0,dvs)
150198
p = varmap_to_vars(parammap,ps)
151199
lb = varmap_to_vars(lb,dvs)
@@ -154,8 +202,25 @@ function OptimizationProblemExpr{iip}(sys::OptimizationSystem,
154202
f = $f
155203
p = $p
156204
u0 = $u0
205+
grad = $_grad
206+
hess = $_hess
157207
lb = $lb
158208
ub = $ub
159-
OptimizationProblem(f,p;u0=u0,lb=lb,ub=ub,kwargs...)
209+
_f = OptimizationFunction{$iip,typeof(f),typeof(grad),typeof(hess),Nothing,Nothing,Nothing,Nothing}(f,grad,hess,nothing,AutoModelingToolkit(),nothing,nothing,nothing,0)
210+
OptimizationProblem{$iip}(_f,u0,p;lb=lb,ub=ub,kwargs...)
211+
end
212+
end
213+
214+
function OptimizationFunction(f, x, ::AutoModelingToolkit,p = DiffEqBase.NullParameters();
215+
grad=false, hess=false, cons = nothing, cons_j = nothing, cons_h = nothing,
216+
num_cons = 0, chunksize = 1, hv = nothing)
217+
218+
sys = modelingtoolkitize(OptimizationProblem(f,x,p))
219+
u0map = states(sys) .=> x
220+
if p == DiffEqBase.NullParameters()
221+
parammap = DiffEqBase.NullParameters()
222+
else
223+
parammap = parameters(sys) .=> p
160224
end
225+
OptimizationProblem(sys,u0map,parammap,grad=grad,hess=hess).f
161226
end

test/controlsystem.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,7 @@ eqs = [
1313
sys = ControlSystem(loss,eqs,t,[x,v],[u],[p])
1414
dt = 0.1
1515
tspan = (0.0,1.0)
16-
runge_kutta_discretize(sys,dt,tspan)
16+
sys = runge_kutta_discretize(sys,dt,tspan)
17+
18+
u0 = rand(112) # guess for the state values
19+
prob = OptimizationProblem(sys,u0,[0.1],grad=true)

test/modelingtoolkitize.jl

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using OrdinaryDiffEq, ModelingToolkit
1+
using OrdinaryDiffEq, ModelingToolkit, Test
2+
using GalacticOptim, Optim
3+
24
const N = 32
35
const xyd_brusselator = range(0,stop=1,length=N)
46
brusselator_f(x, y, t) = (((x-0.3)^2 + (y-0.6)^2) <= 0.1^2) * (t >= 1.1) * 5.
@@ -38,3 +40,22 @@ prob_ode_brusselator_2d = ODEProblem(brusselator_2d_loop,
3840
u0,(0.,11.5),p)
3941

4042
modelingtoolkitize(prob_ode_brusselator_2d)
43+
44+
## Optimization
45+
46+
rosenbrock(x,p) = (p[1] - x[1])^2 + p[2] * (x[2] - x[1]^2)^2
47+
x0 = zeros(2)
48+
p = [1.0,100.0]
49+
50+
prob = OptimizationProblem(rosenbrock,x0,p)
51+
sys = modelingtoolkitize(prob) # symbolicitize me captain!
52+
53+
prob = OptimizationProblem(sys,x0,p,grad=true,hess=true)
54+
sol = solve(prob,NelderMead())
55+
@test sol.minimum < 1e-8
56+
57+
sol = solve(prob,BFGS())
58+
@test sol.minimum < 1e-8
59+
60+
sol = solve(prob,Newton())
61+
@test sol.minimum < 1e-8

test/optimizationsystem.jl

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using ModelingToolkit, SparseArrays
1+
using ModelingToolkit, SparseArrays, Test, GalacticOptim, Optim
22

33
@variables x y
44
@parameters a b
@@ -21,3 +21,28 @@ generate_function(combinedsys)
2121
generate_gradient(combinedsys)
2222
generate_hessian(combinedsys)
2323
ModelingToolkit.hessian_sparsity(combinedsys)
24+
25+
u0 = [
26+
sys1.x=>1.0
27+
sys1.y=>2.0
28+
sys2.x=>3.0
29+
sys2.y=>4.0
30+
z=>5.0
31+
]
32+
p = [
33+
sys1.a => 6.0
34+
sys1.b => 7.0
35+
sys2.a => 8.0
36+
sys2.b => 9.0
37+
β => 10.0
38+
]
39+
40+
prob = OptimizationProblem(combinedsys,u0,p,grad=true)
41+
sol = solve(prob,NelderMead())
42+
@test sol.minimum < -1e5
43+
44+
prob2 = remake(prob,u0=sol.minimizer)
45+
sol = solve(prob,BFGS(initial_stepnorm=0.0001),allow_f_increases=true)
46+
@test sol.minimum < -1e8
47+
sol = solve(prob2,BFGS(initial_stepnorm=0.0001),allow_f_increases=true)
48+
@test sol.minimum < -1e9

0 commit comments

Comments
 (0)