Skip to content

Commit 522fbb9

Browse files
committed
Merge branch 'master' into myb_fb/simplify_clock
2 parents a12ce10 + bbe5081 commit 522fbb9

18 files changed

+790
-232
lines changed

.github/workflows/Downstream.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
- {user: SciML, repo: CellMLToolkit.jl, group: All}
2323
- {user: SciML, repo: SBMLToolkit.jl, group: All}
2424
- {user: SciML, repo: NeuralPDE.jl, group: NNPDE}
25-
- {user: SciML, repo: DataDrivenDiffEq.jl, group: Standard}
25+
#- {user: SciML, repo: DataDrivenDiffEq.jl, group: Standard}
2626
- {user: SciML, repo: StructuralIdentifiability.jl, group: All}
2727
- {user: SciML, repo: ModelingToolkitStandardLibrary.jl}
2828
- {user: SciML, repo: ModelOrderReduction.jl, group: All}

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ModelingToolkit"
22
uuid = "961ee093-0014-501f-94e3-6117800e7a78"
33
authors = ["Yingbo Ma <[email protected]>", "Chris Rackauckas <[email protected]> and contributors"]
4-
version = "8.30.0"
4+
version = "8.32.0"
55

66
[deps]
77
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
@@ -72,7 +72,7 @@ NonlinearSolve = "0.3.8"
7272
RecursiveArrayTools = "2.3"
7373
Reexport = "0.2, 1"
7474
RuntimeGeneratedFunctions = "0.4.3, 0.5"
75-
SciMLBase = "1.60.0"
75+
SciMLBase = "1.70.0"
7676
Setfield = "0.7, 0.8, 1"
7777
SpecialFunctions = "0.7, 0.8, 0.9, 0.10, 1.0, 2"
7878
StaticArrays = "0.10, 0.11, 0.12, 1.0"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
[![Join the chat at https://julialang.zulipchat.com #sciml-bridged](https://img.shields.io/static/v1?label=Zulip&message=chat&color=9558b2&labelColor=389826)](https://julialang.zulipchat.com/#narrow/stream/279055-sciml-bridged)
55
[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](http://mtk.sciml.ai/stable/)
6-
[![Global Docs](https://img.shields.io/badge/docs-SciML-blue.svg)](https://docs.sciml.ai/dev/modules/ModelingToolkit/)
6+
[![Global Docs](https://img.shields.io/badge/docs-SciML-blue.svg)](https://docs.sciml.ai/ModelingToolkit/stable/)
77

88
[![codecov](https://codecov.io/gh/SciML/ModelingToolkit.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/SciML/ModelingToolkit.jl)
99
[![Coverage Status](https://coveralls.io/repos/github/SciML/ModelingToolkit.jl/badge.svg?branch=master)](https://coveralls.io/github/SciML/ModelingToolkit.jl?branch=master)

docs/Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
33
DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa"
44
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
55
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
6-
Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba"
76
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
87
ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78"
98
NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
109
Optim = "429524aa-4258-5aef-a3af-852621145aeb"
10+
Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba"
11+
OptimizationOptimJL = "36348300-93cb-4f02-beb5-3c3902f8871e"
1112
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
1213
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
1314
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"

docs/src/systems/OptimizationSystem.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ OptimizationSystem
88

99
## Composition and Accessor Functions
1010

11-
- `get_eqs(sys)` or `equations(sys)`: The equation to be minimized.
11+
- `get_op(sys)` or `objective(sys)`: The objective to be minimized.
1212
- `get_states(sys)` or `states(sys)`: The set of states for the optimization.
1313
- `get_ps(sys)` or `parameters(sys)`: The parameters for the optimization.
14+
- `get_constraints(sys)` or `constraints(sys)`: The constraints for the optimization.
1415

1516
## Transformations
1617

docs/src/tutorials/optimization.md

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,91 @@
11
# Modeling Optimization Problems
22

3-
```julia
4-
using ModelingToolkit, Optimization, OptimizationOptimJL
3+
## Rosenbrock Function in 2D
4+
Let's solve the classical _Rosenbrock function_ in two dimensions.
55

6-
@variables x y
7-
@parameters a b
6+
First, we need to make some imports.
7+
```@example rosenbrock_2d
8+
using ModelingToolkit, Optimization, OptimizationOptimJL
9+
```
10+
Now we can define our optimization problem.
11+
```@example rosenbrock_2d
12+
@variables begin
13+
x, [bounds = (-2.0, 2.0)]
14+
y, [bounds = (-1.0, 3.0)]
15+
end
16+
@parameters a = 1 b = 1
817
loss = (a - x)^2 + b * (y - x^2)^2
9-
@named sys = OptimizationSystem(loss,[x,y],[a,b])
18+
@named sys = OptimizationSystem(loss, [x, y], [a, b])
19+
```
20+
21+
A visualization of the objective function is depicted below.
22+
```@eval
23+
using Plots
24+
x = -2:0.01:2
25+
y = -1:0.01:3
26+
contour(x, y, (x,y) -> (1 - x)^2 + 100 * (y - x^2)^2, fill=true, color=:viridis, ratio=:equal, xlims=(-2, 2))
27+
savefig("obj_fun.png"); nothing # hide
28+
```
29+
30+
![plot of the Rosenbrock function](obj_fun.png)
31+
32+
### Explanation
33+
Every optimization problem consists of a set of _optimization variables_. In this case we create two variables. Additionally we assign _box constraints_ for each of them. In the next step we create two parameters for the problem with `@parameters`. While it is not needed to do this it makes it easier to `remake` the problem later with different values for the parameters. The _objective function_ is specified as well and finally everything is used to construct an `OptimizationSystem`.
1034

35+
## Building and Solving the Optimization Problem
36+
Next the actual `OptimizationProblem` can be created. At this stage an initial guess `u0` for the optimization variables needs to be provided via map, using the symbols from before. Concrete values for the parameters of the system can also be provided or changed. However, if the parameters have default values assigned they are used automatically.
37+
```@example rosenbrock_2d
1138
u0 = [
12-
x=>1.0
13-
y=>2.0
39+
x => 1.0
40+
y => 2.0
1441
]
1542
p = [
16-
a => 6.0
17-
b => 7.0
43+
a => 1.0
44+
b => 100.0
45+
]
46+
47+
prob = OptimizationProblem(sys, u0, p, grad=true, hess=true)
48+
solve(prob, GradientDescent())
49+
```
50+
51+
## Rosenbrock Function with Constraints
52+
```@example rosenbrock_2d_cstr
53+
using ModelingToolkit, Optimization, OptimizationOptimJL
54+
55+
@variables begin
56+
x, [bounds = (-2.0, 2.0)]
57+
y, [bounds = (-1.0, 3.0)]
58+
end
59+
@parameters a = 1 b = 100
60+
loss = (a - x)^2 + b * (y - x^2)^2
61+
cons = [
62+
x^2 + y^2 ≲ 1,
1863
]
64+
@named sys = OptimizationSystem(loss, [x, y], [a, b], constraints = cons)
65+
u0 = [
66+
x => 1.0
67+
y => 2.0
68+
]
69+
prob = OptimizationProblem(sys, u0, grad=true, hess=true)
70+
solve(prob, IPNewton())
71+
```
1972

20-
prob = OptimizationProblem(sys,u0,p,grad=true,hess=true)
21-
solve(prob,Newton())
73+
A visualization of the objective function and the inequality constraint is depicted below.
74+
```@eval
75+
using Plots
76+
x = -2:0.01:2
77+
y = -1:0.01:3
78+
contour(x, y, (x,y) -> (1 - x)^2 + 100 * (y - x^2)^2, fill=true, color=:viridis, ratio=:equal, xlims=(-2, 2))
79+
contour!(x, y, (x, y) -> x^2 + y^2, levels=[1], color=:lightblue, line=4)
80+
savefig("obj_fun_c.png"); nothing # hide
2281
```
2382

83+
![plot of the Rosenbrock function with constraint](obj_fun_c.png)
84+
85+
### Explanation
86+
Equality and inequality constraints can be added to the `OptimizationSystem`. An equality constraint can be specified via and `Equation`, e.g., `x^2 + y^2 ~ 1`. While inequality constraints via an `Inequality`, e.g., `x^2 + y^2 ≲ 1`. The syntax is here `\lesssim` and `\gtrsim`.
87+
88+
## Nested Systems
2489
Needs more text but it's super cool and auto-parallelizes and sparsifies too.
2590
Plus you can hierarchically nest systems to have it generate huge
2691
optimization problems.

src/ModelingToolkit.jl

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,15 @@ import Graphs: SimpleDiGraph, add_edge!, incidence_matrix
6767
for fun in [:toexpr]
6868
@eval begin
6969
function $fun(eq::Equation; kw...)
70-
Expr(:(=), $fun(eq.lhs; kw...), $fun(eq.rhs; kw...))
70+
Expr(:call, :(==), $fun(eq.lhs; kw...), $fun(eq.rhs; kw...))
71+
end
72+
73+
function $fun(ineq::Inequality; kw...)
74+
if ineq.relational_op == Symbolics.leq
75+
Expr(:call, :(<=), $fun(ineq.lhs; kw...), $fun(ineq.rhs; kw...))
76+
else
77+
Expr(:call, :(>=), $fun(ineq.lhs; kw...), $fun(ineq.rhs; kw...))
78+
end
7179
end
7280

7381
$fun(eqs::AbstractArray; kw...) = map(eq -> $fun(eq; kw...), eqs)
@@ -86,6 +94,7 @@ abstract type AbstractTimeDependentSystem <: AbstractSystem end
8694
abstract type AbstractTimeIndependentSystem <: AbstractSystem end
8795
abstract type AbstractODESystem <: AbstractTimeDependentSystem end
8896
abstract type AbstractMultivariateSystem <: AbstractSystem end
97+
abstract type AbstractOptimizationSystem <: AbstractTimeIndependentSystem end
8998

9099
"""
91100
$(TYPEDSIGNATURES)
@@ -139,6 +148,7 @@ include("systems/jumps/jumpsystem.jl")
139148
include("systems/nonlinear/nonlinearsystem.jl")
140149
include("systems/nonlinear/modelingtoolkitize.jl")
141150

151+
include("systems/optimization/constraints_system.jl")
142152
include("systems/optimization/optimizationsystem.jl")
143153

144154
include("systems/pde/pdesystem.jl")
@@ -179,7 +189,7 @@ export OptimizationProblem, OptimizationProblemExpr, constraints
179189
export AutoModelingToolkit
180190
export SteadyStateProblem, SteadyStateProblemExpr
181191
export JumpProblem, DiscreteProblem
182-
export NonlinearSystem, OptimizationSystem
192+
export NonlinearSystem, OptimizationSystem, ConstraintsSystem
183193
export alias_elimination, flatten
184194
export connect, @connector, Connection, Flow, Stream, instream
185195
export isinput, isoutput, getbounds, hasbounds, isdisturbance, istunable, getdist, hasdist,
@@ -192,7 +202,7 @@ export Equation, ConstrainedEquation
192202
export Term, Sym
193203
export SymScope, LocalScope, ParentScope, GlobalScope
194204
export independent_variables, independent_variable, states, parameters, equations, controls,
195-
observed, structure, full_equations
205+
observed, structure, full_equations, objective
196206
export structural_simplify, expand_connections, linearize, linearization_function
197207
export DiscreteSystem, DiscreteProblem
198208

src/constants.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,15 @@ macro constants(xs...)
3232
xs,
3333
toconstant) |> esc
3434
end
35+
36+
"""
37+
Substitute all `@constants` in the given expression
38+
"""
39+
function subs_constants(eqs)
40+
consts = collect_constants(eqs)
41+
if !isempty(consts)
42+
csubs = Dict(c => getdefault(c) for c in consts)
43+
eqs = substitute(eqs, csubs)
44+
end
45+
return eqs
46+
end

src/inputoutput.jl

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -343,14 +343,16 @@ function get_disturbance_system(dist::DisturbanceModel{<:ODESystem})
343343
end
344344

345345
"""
346-
(f_oop, f_ip), augmented_sys, dvs, p = add_input_disturbance(sys, dist::DisturbanceModel)
346+
(f_oop, f_ip), augmented_sys, dvs, p = add_input_disturbance(sys, dist::DisturbanceModel, inputs = nothing)
347347
348348
Add a model of an unmeasured disturbance to `sys`. The disturbance model is an instance of [`DisturbanceModel`](@ref).
349349
350350
The generated dynamics functions `(f_oop, f_ip)` will preserve any state and dynamics associated with disturbance inputs, but the disturbance inputs themselves will not be included as inputs to the generated function. The use case for this is to generate dynamics for state observers that estimate the influence of unmeasured disturbances, and thus require state variables for the disturbance model, but without disturbance inputs since the disturbances are not available for measurement.
351351
352352
`dvs` will be the states of the simplified augmented system, consisting of the states of `sys` as well as the states of the disturbance model.
353353
354+
For MIMO systems, all inputs to the system has to be specified in the argument `inputs`
355+
354356
# Example
355357
The example below builds a double-mass model and adds an integrating disturbance to the input
356358
```julia
@@ -391,18 +393,29 @@ dist = ModelingToolkit.DisturbanceModel(model.torque.tau.u, dmodel)
391393
```
392394
`f_oop` will have an extra state corresponding to the integrator in the disturbance model. This state will not be affected by any input, but will affect the dynamics from where it enters, in this case it will affect additively from `model.torque.tau.u`.
393395
"""
394-
function add_input_disturbance(sys, dist::DisturbanceModel)
396+
function add_input_disturbance(sys, dist::DisturbanceModel, inputs = nothing)
395397
t = get_iv(sys)
396398
@variables d(t)=0 [disturbance = true]
397-
@variables u(t)=0 [input = true]
399+
@variables u(t)=0 [input = true] # New system input
398400
dsys = get_disturbance_system(dist)
399401

402+
if inputs === nothing
403+
all_inputs = [u]
404+
else
405+
i = findfirst(isequal(dist.input), inputs)
406+
if i === nothing
407+
throw(ArgumentError("Input $(dist.input) indicated in the disturbance model was not found among inputs specified to add_input_disturbance"))
408+
end
409+
all_inputs = copy(inputs)
410+
all_inputs[i] = u # The input where the disturbance acts is no longer an input, the new input is u
411+
end
412+
400413
eqs = [dsys.input.u[1] ~ d
401414
dist.input ~ u + dsys.output.u[1]]
402415

403416
augmented_sys = ODESystem(eqs, t, systems = [sys, dsys], name = gensym(:outer))
404417

405-
(f_oop, f_ip), dvs, p = generate_control_function(augmented_sys, [u],
418+
(f_oop, f_ip), dvs, p = generate_control_function(augmented_sys, all_inputs,
406419
[d])
407420
(f_oop, f_ip), augmented_sys, dvs, p
408421
end

src/systems/diffeqs/abstractodesystem.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ function ODEFunctionExpr{iip}(sys::AbstractODESystem, dvs = states(sys),
562562
syms = $(Symbol.(states(sys))),
563563
indepsym = $(QuoteNode(Symbol(get_iv(sys)))),
564564
paramsyms = $(Symbol.(parameters(sys))),
565-
sparsity = $(jacobian_sparsity(sys)))
565+
sparsity = $sparsity ? $(jacobian_sparsity(sys)) : $nothing)
566566
end
567567
!linenumbers ? striplines(ex) : ex
568568
end

0 commit comments

Comments
 (0)