Skip to content

Commit 844d012

Browse files
Constraints and expression handling in OptimizationProblem
1 parent 9cb6a4d commit 844d012

File tree

2 files changed

+137
-36
lines changed

2 files changed

+137
-36
lines changed

src/systems/optimization/optimizationsystem.jl

Lines changed: 125 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ struct OptimizationSystem <: AbstractTimeIndependentSystem
2626
"""Array variables."""
2727
var_to_name::Any
2828
observed::Vector{Equation}
29-
equality_constraints::Vector{Equation}
30-
inequality_constraints::Vector
29+
constraints::Vector
3130
"""
3231
Name: the name of the system. These are required to have unique names.
3332
"""
@@ -41,24 +40,22 @@ struct OptimizationSystem <: AbstractTimeIndependentSystem
4140
parameters are not supplied in `ODEProblem`.
4241
"""
4342
defaults::Dict
44-
function OptimizationSystem(op, states, ps, var_to_name, observed, equality_constraints,
45-
inequality_constraints, name, systems, defaults;
43+
function OptimizationSystem(op, states, ps, var_to_name, observed,
44+
constraints, name, systems, defaults;
4645
checks::Bool = true)
4746
if checks
4847
check_units(op)
4948
check_units(observed)
50-
check_units(equality_constraints)
51-
all_dimensionless([states; ps]) || check_units(inequality_constraints)
49+
all_dimensionless([states; ps]) || check_units(constraints)
5250
end
53-
new(op, states, ps, var_to_name, observed, equality_constraints,
54-
inequality_constraints, name, systems, defaults)
51+
new(op, states, ps, var_to_name, observed,
52+
constraints, name, systems, defaults)
5553
end
5654
end
5755

5856
function OptimizationSystem(op, states, ps;
5957
observed = [],
60-
equality_constraints = Equation[],
61-
inequality_constraints = [],
58+
constraints = [],
6259
default_u0 = Dict(),
6360
default_p = Dict(),
6461
defaults = _merge(Dict(default_u0), Dict(default_p)),
@@ -85,7 +82,7 @@ function OptimizationSystem(op, states, ps;
8582
isempty(observed) || collect_var_to_name!(var_to_name, (eq.lhs for eq in observed))
8683
OptimizationSystem(value(op), states, ps, var_to_name,
8784
observed,
88-
equality_constraints, inequality_constraints,
85+
constraints,
8986
name, systems, defaults; checks = checks)
9087
end
9188

@@ -133,6 +130,13 @@ function DiffEqBase.OptimizationProblem(sys::OptimizationSystem, args...; kwargs
133130
DiffEqBase.OptimizationProblem{true}(sys::OptimizationSystem, args...; kwargs...)
134131
end
135132

133+
function rep_pars_vals!(e::Expr, p)
134+
rep_pars_vals!.(e.args, Ref(p))
135+
replace!(e.args, p...)
136+
end
137+
138+
function rep_pars_vals!(e, p) end
139+
136140
"""
137141
```julia
138142
function DiffEqBase.OptimizationProblem{iip}(sys::OptimizationSystem,u0map,
@@ -160,9 +164,21 @@ function DiffEqBase.OptimizationProblem{iip}(sys::OptimizationSystem, u0map,
160164
dvs = states(sys)
161165
ps = parameters(sys)
162166

167+
defs = defaults(sys)
168+
defs = mergedefaults(defs, parammap, ps)
169+
defs = mergedefaults(defs, u0map, dvs)
170+
171+
u0 = varmap_to_vars(u0map, dvs; defaults = defs, tofloat = false)
172+
p = varmap_to_vars(parammap, ps; defaults = defs, tofloat = false, use_union)
173+
lb = varmap_to_vars(lb, dvs; check = false, tofloat = false, use_union)
174+
ub = varmap_to_vars(ub, dvs; check = false, tofloat = false, use_union)
175+
163176
f = generate_function(sys, checkbounds = checkbounds, linenumbers = linenumbers,
164177
expression = Val{false})
165178

179+
obj_expr = toexpr(equations(sys))
180+
pairs_arr = p isa SciMLBase.NullParameters ? [Symbol(_s) => Expr(:ref, :x, i) for (i, _s) in enumerate(dvs)] : [[Symbol(_s) => Expr(:ref, :x, i) for (i, _s) in enumerate(dvs)]..., [Symbol(_p) => p[i] for (i, _p) in enumerate(ps)]...]
181+
rep_pars_vals!(obj_expr, pairs_arr)
166182
if grad
167183
grad_oop, grad_iip = generate_gradient(sys, checkbounds = checkbounds,
168184
linenumbers = linenumbers,
@@ -190,20 +206,45 @@ function DiffEqBase.OptimizationProblem{iip}(sys::OptimizationSystem, u0map,
190206
hess_prototype = nothing
191207
end
192208

193-
_f = DiffEqBase.OptimizationFunction{iip}(f,
209+
if length(sys.constraints) > 0
210+
@named cons_sys = NonlinearSystem(sys.constraints, dvs, ps)
211+
cons = generate_function(cons_sys, checkbounds = checkbounds, linenumbers = linenumbers,
212+
expression = Val{false})[1]
213+
cons_j = generate_jacobian(cons_sys; expression=Val{false}, sparse=sparse)[2]
214+
cons_h = generate_hessian(cons_sys; expression = Val{false}, sparse =sparse)[2]
215+
216+
cons_expr = toexpr(equations(cons_sys))
217+
rep_pars_vals!.(cons_expr, Ref(pairs_arr))
218+
219+
if sparse
220+
cons_jac_prototype = jacobian_sparsity(cons_sys)
221+
cons_hess_prototype = hessian_sparsity(cons_sys)
222+
else
223+
cons_jac_prototype = nothing
224+
cons_hess_prototype = nothing
225+
end
226+
227+
_f = DiffEqBase.OptimizationFunction{iip}(f,
194228
SciMLBase.NoAD();
195229
grad = _grad,
196230
hess = _hess,
197-
hess_prototype = hess_prototype)
198-
199-
defs = defaults(sys)
200-
defs = mergedefaults(defs, parammap, ps)
201-
defs = mergedefaults(defs, u0map, dvs)
231+
hess_prototype = hess_prototype,
232+
cons = cons,
233+
cons_j = cons_j,
234+
cons_h = cons_h,
235+
cons_jac_prototype = cons_jac_prototype,
236+
cons_hess_prototype = cons_hess_prototype,
237+
expr = obj_expr,
238+
cons_expr = cons_expr)
239+
else
240+
_f = DiffEqBase.OptimizationFunction{iip}(f,
241+
SciMLBase.NoAD();
242+
grad = _grad,
243+
hess = _hess,
244+
hess_prototype = hess_prototype,
245+
expr = obj_expr)
246+
end
202247

203-
u0 = varmap_to_vars(u0map, dvs; defaults = defs, tofloat = false)
204-
p = varmap_to_vars(parammap, ps; defaults = defs, tofloat = false, use_union)
205-
lb = varmap_to_vars(lb, dvs; check = false, tofloat = false, use_union)
206-
ub = varmap_to_vars(ub, dvs; check = false, tofloat = false, use_union)
207248
OptimizationProblem{iip}(_f, u0, p; lb = lb, ub = ub, kwargs...)
208249
end
209250

@@ -272,18 +313,68 @@ function OptimizationProblemExpr{iip}(sys::OptimizationSystem, u0,
272313
p = varmap_to_vars(parammap, ps; defaults = defs, tofloat = false, use_union)
273314
lb = varmap_to_vars(lb, dvs; check = false, tofloat = false, use_union)
274315
ub = varmap_to_vars(ub, dvs; check = false, tofloat = false, use_union)
275-
quote
276-
f = $f
277-
p = $p
278-
u0 = $u0
279-
grad = $_grad
280-
hess = $_hess
281-
lb = $lb
282-
ub = $ub
283-
_f = OptimizationFunction{iip}(f, SciMLBase.NoAD();
284-
grad = grad,
285-
hess = hess,
286-
hess_prototype = hess_prototype)
287-
OptimizationProblem{$iip}(_f, u0, p; lb = lb, ub = ub, kwargs...)
316+
317+
obj_expr = toexpr(equations(sys))
318+
pairs_arr = p isa SciMLBase.NullParameters ? [Symbol(_s) => Expr(:ref, :x, i) for (i, _s) in enumerate(dvs)] : [[Symbol(_s) => Expr(:ref, :x, i) for (i, _s) in enumerate(dvs)]..., [Symbol(_p) => p[i] for (i, _p) in enumerate(ps)]...]
319+
rep_pars_vals!(obj_expr, pairs_arr)
320+
321+
if length(sys.constraints) > 0
322+
@named cons_sys = NonlinearSystem(sys.constraints, dvs, ps)
323+
cons = generate_function(cons_sys, checkbounds = checkbounds, linenumbers = linenumbers,
324+
expression = Val{false})[1]
325+
cons_j = generate_jacobian(cons_sys; expression=Val{false}, sparse=sparse)[2]
326+
327+
cons_h = generate_hessian(cons_sys; expression = Val{false}, sparse =sparse)[2]
328+
329+
cons_expr = toexpr(equations(cons_sys))
330+
rep_pars_vals!.(cons_expr, Ref(pairs_arr))
331+
332+
if sparse
333+
cons_jac_prototype = jacobian_sparsity(cons_sys)
334+
cons_hess_prototype = hessian_sparsity(cons_sys)
335+
else
336+
cons_jac_prototype = nothing
337+
cons_hess_prototype = nothing
338+
end
339+
quote
340+
f = $f
341+
p = $p
342+
u0 = $u0
343+
grad = $_grad
344+
hess = $_hess
345+
lb = $lb
346+
ub = $ub
347+
cons = $cons
348+
cons_j = $cons_j
349+
cons_h = $cons_h
350+
_f = OptimizationFunction{iip}(f, SciMLBase.NoAD();
351+
grad = grad,
352+
hess = hess,
353+
hess_prototype = hess_prototype,
354+
cons = cons,
355+
cons_j = cons_j,
356+
cons_h = cons_h,
357+
cons_jac_prototype = cons_jac_prototype,
358+
cons_hess_prototype = cons_hess_prototype,
359+
expr = obj_expr,
360+
cons_expr = cons_expr)
361+
OptimizationProblem{$iip}(_f, u0, p; lb = lb, ub = ub, kwargs...)
362+
end
363+
else
364+
quote
365+
f = $f
366+
p = $p
367+
u0 = $u0
368+
grad = $_grad
369+
hess = $_hess
370+
lb = $lb
371+
ub = $ub
372+
_f = OptimizationFunction{iip}(f, SciMLBase.NoAD();
373+
grad = grad,
374+
hess = hess,
375+
hess_prototype = hess_prototype,
376+
expr = obj_expr)
377+
OptimizationProblem{$iip}(_f, u0, p; lb = lb, ub = ub, kwargs...)
378+
end
288379
end
289380
end

test/optimizationsystem.jl

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
using ModelingToolkit, SparseArrays, Test, Optimization, OptimizationOptimJL
1+
using ModelingToolkit, SparseArrays, Test, Optimization, OptimizationOptimJL, OptimizationMOI, Ipopt, AmplNLWriter, Ipopt_jll
22

33
@variables x y
44
@parameters a b
55
loss = (a - x)^2 + b * (y - x^2)^2
66
sys1 = OptimizationSystem(loss, [x, y], [a, b], name = :sys1)
7-
sys2 = OptimizationSystem(loss, [x, y], [a, b], name = :sys2)
7+
8+
cons2 = [x^2 + y^2 ~ 0, y * sin(x) - x ~ 0]
9+
sys2 = OptimizationSystem(loss, [x, y], [a, b], name = :sys2, constraints = cons2)
810

911
@variables z
1012
@parameters β
@@ -47,6 +49,14 @@ sol = solve(prob, BFGS(initial_stepnorm = 0.0001), allow_f_increases = true)
4749
sol = solve(prob2, BFGS(initial_stepnorm = 0.0001), allow_f_increases = true)
4850
@test sol.minimum < -1e9
4951

52+
prob = OptimizationProblem(sys2, [x => 0.0, y => 0.0], [a => 1.0, b => 100.0], lcons = [-1.0, -1.0], ucons = [500.0, 500.0], grad = true, hess = true)
53+
sol = solve(prob, IPNewton(), allow_f_increases = true)
54+
@test sol.minimum < 1.0
55+
sol = solve(prob, Ipopt.Optimizer())
56+
@test sol.minimum < 1.0
57+
sol = solve(prob, AmplNLWriter.Optimizer(Ipopt_jll.amplexe))
58+
@test sol.minimum < 1.0
59+
5060
rosenbrock(x, p) = (p[1] - x[1])^2 + p[2] * (x[2] - x[1]^2)^2
5161
x0 = zeros(2)
5262
_p = [1.0, 100.0]

0 commit comments

Comments
 (0)