Skip to content

Commit ab8f017

Browse files
authored
Direct Problem (#234)
* Refine problems and add direct prob * Update docs and remove pkg loading * Clean dispatch for koopman * Clean up tests * Scalarize parameters * Update docs * Add more tests for problem * More koopman tests
1 parent dc53e6e commit ab8f017

File tree

12 files changed

+717
-267
lines changed

12 files changed

+717
-267
lines changed

docs/src/prob_and_solve.md

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,28 @@
22

33
As can be seen from the [introduction examples](@id Quickstart), [DataDrivenDiffEq.jl](https://github.com/SciML/DataDrivenDiffEq.jl) tries to structurize the workflow in a similar fashion to other [SciML](https://sciml.ai/) packages by defining a [`DataDrivenProblem`](@ref), dispatching on the `solve` command to return a [`DataDrivenSolution`](@ref).
44

5-
A problem in the sense of identification, estimation or inference is defined by the data describing it. This data contains at least measurements of the states `X`, which would be sufficient to describe a `DiscreteDataDrivenProblem` with unit time steps similar to the [first example on dynamic mode decomposition](@ref Linear-Systems-via-Dynamic-Mode-Decomposition). Of course we can extend this to include time points `t`, consecutive measurements `` at the next time point or control signals `U` or a function describing those `u(x,p,t)`. Additionally, any parameters `p` known a priori can be included in the problem. In practice, this looks like
5+
A problem in the sense of identification, estimation or inference is defined by the data describing it. This data contains at least measurements of the states `X`, which would be sufficient to describe a `DiscreteDataDrivenProblem` with unit time steps similar to the [first example on dynamic mode decomposition](@ref Linear-Systems-via-Dynamic-Mode-Decomposition). Of course we can extend this to include time points `t`, control signals `U` or a function describing those `u(x,p,t)`. Additionally, any parameters `p` known a priori can be included in the problem. In practice, this looks like
66

77
```julia
88
problem = DiscreteDataDrivenProblem(X)
99
problem = DiscreteDataDrivenProblem(X, t)
10-
problem = DiscreteDataDrivenProblem(X, t, X̃)
11-
problem = DiscreteDataDrivenProblem(X, t, X̃, U = U)
12-
problem = DiscreteDataDrivenProblem(X, t, X̃, U = U, p = p)
13-
problem = DiscreteDataDrivenProblem(X, t, X̃, U = (x,p,t)->u(x,p,t))
10+
problem = DiscreteDataDrivenProblem(X, t, U)
11+
problem = DiscreteDataDrivenProblem(X, t, U, p = p)
12+
problem = DiscreteDataDrivenProblem(X, t, (x,p,t)->u(x,p,t))
1413
```
1514

1615
Similarly, a `ContinuousDataDrivenProblem` would need at least measurements and time-derivatives (`X` and `DX`) or measurements, time information and a way to derive the time derivatives(`X`, `t` and a [Collocation](@ref) method). Again, this can be extended by including a control input as measurements or a function and possible parameters.
1716

1817
```julia
18+
problem = ContinuousDataDrivenProblem(X, DX)
19+
problem = ContinuousDataDrivenProblem(X, t, DX)
20+
problem = ContinuousDataDrivenProblem(X, t, DX, U, p = p)
21+
problem = ContinuousDataDrivenProblem(X, t, DX, (x,p,t)->u(x,p,t))
22+
# Using collocation
1923
problem = ContinuousDataDrivenProblem(X, t, InterpolationMethod())
20-
problem = ContinuousDataDrivenProblem(X, DX = DX)
21-
problem = ContinuousDataDrivenProblem(X, t, DX = DX)
22-
problem = ContinuousDataDrivenProblem(X, t, DX = DX, U = U)
23-
problem = ContinuousDataDrivenProblem(X, t, DX = DX, U = U, p = p)
24-
problem = ContinuousDataDrivenProblem(X, t, DX = DX, U = (x,p,t)->u(x,p,t))
24+
problem = ContinuousDataDrivenProblem(X, t, GaussianKernel())
25+
problem = ContinuousDataDrivenProblem(X, t, U, InterpolationMethod())
26+
problem = ContinuousDataDrivenProblem(X, t, U, GaussianKernel(), p = p)
2527
```
2628

2729
You can also directly use a `DESolution` as an input to your [`DataDrivenProblem`](@ref):
@@ -33,6 +35,16 @@ problem = DataDrivenProblem(sol; kwargs...)
3335
which evaluates the function at the specific timepoints `t` using the parameters `p` of the original problem instead of
3436
using the interpolation. If you want to use the interpolated data, add the additional keyword `use_interpolation = true`.
3537

38+
An additional type of problem is the `DirectDataDrivenProblem`, which does not assume any kind of causal relationship. It is defined by `X` and an observed output `Y` in addition to the usual arguments:
39+
40+
```julia
41+
problem = DirectDataDrivenProblem(X, Y)
42+
problem = DirectDataDrivenProblem(X, t, Y)
43+
problem = DirectDataDrivenProblem(X, t, Y, U)
44+
problem = DirectDataDrivenProblem(X, t, Y, p = p)
45+
problem = DirectDataDrivenProblem(X, t, Y, (x,p,t)->u(x,p,t), p = p)
46+
```
47+
3648
Next up, we choose a method to `solve` the [`DataDrivenProblem`](@ref). Depending on the input arguments and the type of problem, the function will return a result derived via [`Koopman`](@ref) or [`Sparse Optimization`](@ref) methods. Different options can be provided as well as a [`Basis`](@ref) used for lifting the measurements, to control different options like rounding, normalization or the progressbar depending on the inference method. Possible options are provided [below](@ref optional_arguments).
3749

3850
```julia

docs/src/quickstart.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ savefig("DMD_Example_1.png") # hide
2929
To estimate the underlying operator in the states ``u_1, u_2``, we simply define a discrete [`DataDrivenProblem`](@ref) using the measurements and time and `solve` the estimation problem using the [`DMDSVD`](@ref) algorithm for approximating the operator.
3030

3131
```@example 4
32-
X = Array(sol)
3332
34-
prob = DiscreteDataDrivenProblem(X, t = sol.t)
33+
prob = DiscreteDataDrivenProblem(sol)
3534
3635
res = solve(prob, DMDSVD(), digits = 1)
3736
system = result(res)
@@ -114,6 +113,7 @@ using ModelingToolkit
114113
using OrdinaryDiffEq
115114
using Plots
116115
using Random
116+
using Symbolics: scalarize
117117
118118
Random.seed!(1111) # Due to the noise
119119
@@ -166,8 +166,11 @@ and returns a pareto optimal solution of the underlying [`sparse_regression!`](@
166166
```@example 1
167167
@variables u[1:2] c[1:1]
168168
@parameters w[1:2]
169+
u = scalarize(u)
170+
c = scalarize(c)
171+
w = scalarize(w)
169172
170-
h = Num[sin(w[1]*u[1]);cos(w[2]*u[1]); polynomial_basis(u, 5); c]
173+
h = Num[sin.(w[1].*u[1]);cos.(w[2].*u[1]); polynomial_basis(u, 5); c]
171174
172175
basis = Basis(h, u, parameters = w, controls = c)
173176
@@ -248,7 +251,7 @@ for (i, xi) in enumerate(eachcol(X))
248251
DX[:, i] = michaelis_menten(xi, [], ts[i])
249252
end
250253
251-
prob = ContinuousDataDrivenProblem(X, ts, DX = DX)
254+
prob = ContinuousDataDrivenProblem(X, ts, DX)
252255
253256
p1 = plot(ts, X', label = ["Measurement" nothing], color = :black, style = :dash, legend = :bottomleft, ylabel ="Measurement") # hide
254257
p2 = plot(ts, DX', label = nothing, color = :black, style = :dash, ylabel = "Derivative", xlabel = "Time [s]") # hide

src/DataDrivenDiffEq.jl

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ abstract type CollocationKernel end
3333
abstract type AbstractKoopmanAlgorithm end
3434

3535
# Problem and solution
36-
abstract type AbstractDataDrivenProblem end
36+
abstract type AbstractDataDrivenProblem{dType, cType, probType} end
3737
abstract type AbstractDataDrivenSolution end
3838

3939

@@ -81,13 +81,31 @@ export update!
8181
include("./koopman/algorithms.jl")
8282
export DMDPINV, DMDSVD, TOTALDMD
8383

84+
85+
8486
## Problem and Solution
87+
# Use to distinguish the problem types
88+
@enum DDProbType begin
89+
Direct=1 # Direct problem without further information
90+
Discrete=2 # Time discrete problem
91+
Continuous=3 # Time continous problem
92+
end
93+
94+
95+
# Define some alias type for easier dispatch
96+
const AbstractDirectProb{N,C} = AbstractDataDrivenProblem{N,C,DDProbType(1)}
97+
const AbstractDiscreteProb{N,C} = AbstractDataDrivenProblem{N,C,DDProbType(2)}
98+
const AbstracContProb{N,C} = AbstractDataDrivenProblem{N,C,DDProbType(3)}
99+
100+
85101
include("./problem.jl")
102+
86103
export DataDrivenProblem
87-
export DiscreteDataDrivenProblem, ContinuousDataDrivenProblem
88-
export has_timepoints, has_inputs, has_observations, has_derivatives
104+
export DiscreteDataDrivenProblem, ContinuousDataDrivenProblem, DirectDataDrivenProblem
105+
export is_autonomous, is_discrete, is_direct, is_continuous, is_parametrized, has_timepoints
89106
export is_valid
90107

108+
91109
include("./solution.jl")
92110
export DataDrivenSolution
93111
export result, parameters, parameter_map, metrics, algorithm, inputs

0 commit comments

Comments
 (0)