Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ dev_subpkg("DataDrivenDMD")
dev_subpkg("DataDrivenSparse")
dev_subpkg("DataDrivenSR")


using Documenter
using DataDrivenDiffEq
using DataDrivenDMD
Expand Down Expand Up @@ -78,7 +77,7 @@ makedocs(sitename = "DataDrivenDiffEq.jl",
"http://cwrowley.princeton.edu/papers/Hemati-2017a.pdf",
"https://royalsocietypublishing.org/doi/10.1098/rspa.2020.0279",
"https://www.pnas.org/doi/10.1073/pnas.1517384113",
"https://link.springer.com/article/10.1007/s00332-015-9258-5",
"https://link.springer.com/article/10.1007/s00332-015-9258-5"
],
format = Documenter.HTML(assets = ["assets/favicon.ico"],
canonical = "https://docs.sciml.ai/DataDrivenDiffEq/stable/"),
Expand Down
10 changes: 8 additions & 2 deletions lib/DataDrivenDMD/src/algorithms.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ K = Y / X
where `Y` and `X` are data matrices. Returns a `Eigen` factorization of the operator.

# Fields

$(FIELDS)

# Signatures

$(SIGNATURES)
"""
mutable struct DMDPINV <: AbstractKoopmanAlgorithm end;
Expand Down Expand Up @@ -85,11 +87,12 @@ where `Y` and `X = U*Σ*V'` are data matrices. The singular value decomposition
the `truncation` parameter, which can either be an `Int` indicating an index-based truncation or a `Real`
indicating a tolerance-based truncation. Returns a `Eigen` factorization of the operator.


# Fields

$(FIELDS)

# Signatures

$(SIGNATURES)
"""
mutable struct DMDSVD{T} <: AbstractKoopmanAlgorithm where {T <: Number}
Expand Down Expand Up @@ -153,9 +156,11 @@ entries bigger than `rtol*maximum(Σ)`. If `rtol` is an integer, the reduced SVD
for computation.

# Fields

$(FIELDS)

# Signatures

$(SIGNATURES)
"""
mutable struct TOTALDMD{R, A} <:
Expand Down Expand Up @@ -187,17 +192,18 @@ end
"""
$(TYPEDEF)


Approximates the Koopman operator `K` via the forward-backward DMD.
It is assumed that `K = sqrt(K₁*inv(K₂))`, where `K₁` is the approximation via forward and `K₂` via [DMDSVD](@ref). Based on [this paper](https://arxiv.org/pdf/1507.02264).

If `truncation` ∈ (0, 1) is given, the singular value decomposition is reduced to include only
entries bigger than `truncation*maximum(Σ)`. If `truncation` is an integer, the reduced SVD up to `truncation` is used for computation.

# Fields

$(FIELDS)

# Signatures

$(SIGNATURES)
"""
mutable struct FBDMD{R} <: AbstractKoopmanAlgorithm where {R <: Number}
Expand Down
8 changes: 5 additions & 3 deletions lib/DataDrivenDMD/src/type.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
$(TYPEDEF)

# Fields

$(FIELDS)

## Note
Expand Down Expand Up @@ -104,7 +105,8 @@ function operator(k::Koopman{<:Any, <:Any, <:Any, false})
throw(AssertionError("Koopman is continuous."))
end

"""_
"""
_
$(SIGNATURES)

Return the approximation of the continuous Koopman generator stored in `k`.
Expand All @@ -131,8 +133,8 @@ $(SIGNATURES)

Returns `true` if either:

+ the Koopman operator has just eigenvalues with magnitude less than one or
+ the Koopman generator has just eigenvalues with a negative real part
- the Koopman operator has just eigenvalues with magnitude less than one or
- the Koopman generator has just eigenvalues with a negative real part
"""
is_stable(k::Koopman{<:Any, true}) = all(real.(eigvals(k)) .< real.(one(eltype(k))))
is_stable(k::Koopman{<:Any, false}) = all(real.(eigvals(k)) .< real.(zero(eltype(k))))
Expand Down
3 changes: 2 additions & 1 deletion lib/DataDrivenLux/src/caches/cache.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ end

function init_cache(x::X where {X <: AbstractDAGSRAlgorithm},
basis::Basis, problem::DataDrivenProblem; kwargs...)
(; rng, keep, observed, populationsize, optimizer, optim_options, optimiser, loss) = x.options
(; rng, keep, observed, populationsize, optimizer,
optim_options, optimiser, loss) = x.options
# Derive the model
dataset = Dataset(problem)
TData = eltype(dataset)
Expand Down
1 change: 1 addition & 0 deletions lib/DataDrivenLux/src/caches/candidate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ A container holding all the information for the current candidate solution
to the symbolic regression problem.

# Fields

$(FIELDS)
"""
@concrete struct Candidate <: StatsBase.StatisticalModel
Expand Down
1 change: 1 addition & 0 deletions lib/DataDrivenLux/src/lux/graph.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ A container for a layered directed acyclic graph consisting of
different [`DecisionLayer`](@ref)s.

# Fields

$(FIELDS)
"""
@concrete struct LayeredDAG <: AbstractLuxWrapperLayer{:layers}
Expand Down
3 changes: 2 additions & 1 deletion lib/DataDrivenLux/src/lux/layer.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""
$(TYPEDEF)

A container for multiple [`DecisionNodes`](@ref).
A container for multiple [`DecisionNodes`](@ref).
It accumulates all outputs of the nodes.

# Fields

$(FIELDS)
"""
@concrete struct FunctionLayer <: AbstractLuxWrapperLayer{:nodes}
Expand Down
4 changes: 2 additions & 2 deletions lib/DataDrivenLux/src/lux/node.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"""
$(TYPEDEF)

A layer representing a decision node with a single function
A layer representing a decision node with a single function
and a latent array of weights representing a probability distribution over the inputs.

# Fields
$(FIELDS)

$(FIELDS)
"""
@concrete struct FunctionNode <: AbstractLuxWrapperLayer{:node}
node
Expand Down
4 changes: 3 additions & 1 deletion lib/DataDrivenLux/src/lux/simplex.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ end
"""
$(TYPEDEF)

Maps an `AbstractVector` to the probability simplex by adding gumbel distributed
Maps an `AbstractVector` to the probability simplex by adding gumbel distributed
noise and using `softmax` on each row.

# Fields

$(FIELDS)
"""
struct GumbelSoftmax <: AbstractSimplex end
Expand All @@ -41,6 +42,7 @@ $(TYPEDEF)
Assumes an `AbstractVector` is on the probability simplex.

# Fields

$(FIELDS)
"""
struct DirectSimplex <: AbstractSimplex end
Expand Down
11 changes: 8 additions & 3 deletions lib/DataDrivenSR/src/DataDrivenSR.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ $(TYPEDEF)
Options for using SymbolicRegression.jl within the `solve` function.
Automatically creates [`Options`](https://ai.damtp.cam.ac.uk/symbolicregression/stable/api/#Options) with the given specification.
Sorts the operators stored in `functions` into unary and binary operators on conversion.

# Fields

$(FIELDS)
"""
@with_kw struct EQSearch <: AbstractDataDrivenAlgorithm
Expand Down Expand Up @@ -131,7 +133,8 @@ end
function convert_to_basis(paretofrontier, prob)
@unpack alg, basis, problem, options = prob
@unpack eq_options = alg
@unpack maxiters, eval_expresssion, generate_symbolic_parameters, digits, roundingmode = options
@unpack maxiters, eval_expresssion, generate_symbolic_parameters, digits,
roundingmode = options

eqs_ = map(paretofrontier) do dom
node_to_symbolic(dom[end].tree, eq_options)
Expand Down Expand Up @@ -205,9 +208,11 @@ end

function CommonSolve.solve!(ps::InternalDataDrivenProblem{EQSearch})
@unpack alg, basis, testdata, traindata, kwargs = ps
@unpack weights, numprocs, procs, addprocs_function, parallelism, runtests, eq_options = alg
@unpack weights, numprocs, procs, addprocs_function, parallelism, runtests,
eq_options = alg
@unpack traindata, testdata, basis, options = ps
@unpack maxiters, eval_expresssion, generate_symbolic_parameters, digits, roundingmode, selector = options
@unpack maxiters, eval_expresssion, generate_symbolic_parameters,
digits, roundingmode, selector = options
@unpack problem = ps

results = map(traindata) do (X, Y)
Expand Down
7 changes: 6 additions & 1 deletion lib/DataDrivenSparse/src/algorithms/ADMM.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
"""
$(TYPEDEF)
`ADMM` is an implementation of Lasso using the alternating direction methods of multipliers, and
loosely based on [this implementation](https://web.stanford.edu/~boyd/papers/admm/lasso/lasso.html).
loosely based on [this implementation](https://web.stanford.edu/%7Eboyd/papers/admm/lasso/lasso.html).
It solves the following problem

```math
\\argmin_{x} \\frac{1}{2} \\| Ax-b\\|_2 + \\lambda \\|x\\|_1
```

# Fields

$(FIELDS)

# Example

```julia
opt = ADMM()
opt = ADMM(1e-1, 2.0)
Expand Down
2 changes: 2 additions & 0 deletions lib/DataDrivenSparse/src/algorithms/Implicit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ solving the explicit problem, as introduced [here](https://royalsocietypublishin
```

# Fields

$(FIELDS)

# Example

```julia
ImplicitOptimizer(STLSQ())
ImplicitOptimizer(0.1f0, ADMM)
Expand Down
6 changes: 6 additions & 0 deletions lib/DataDrivenSparse/src/algorithms/SR3.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,28 @@ $(TYPEDEF)
`SR3` is an optimizer framework introduced [by Zheng et al., 2018](https://ieeexplore.ieee.org/document/8573778) and used within
[Champion et al., 2019](https://arxiv.org/abs/1906.10612). `SR3` contains a sparsification parameter `λ`, a relaxation `ν`.
It solves the following problem

```math
\\argmin_{x, w} \\frac{1}{2} \\| Ax-b\\|_2 + \\lambda R(w) + \\frac{\\nu}{2}\\|x-w\\|_2
```

Where `R` is a proximal operator, and the result is given by `w`.

# Fields

$(FIELDS)

# Example

```julia
opt = SR3()
opt = SR3(1e-2)
opt = SR3(1e-3, 1.0)
opt = SR3(1e-3, 1.0, SoftThreshold())
```

## Note

Opposed to the original formulation, we use `nu` as a relaxation parameter,
as given in [Champion et al., 2019](https://arxiv.org/abs/1906.10612). In the standard case of
hard thresholding the sparsity is interpreted as `λ = threshold^2 / 2`, otherwise `λ = threshold`.
Expand Down
6 changes: 6 additions & 0 deletions lib/DataDrivenSparse/src/algorithms/STLSQ.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ $(TYPEDEF)
sequentially thresholded least squares iteration. `λ` is the threshold of the iteration.
It is based upon [this Matlab implementation](https://github.com/eurika-kaiser/SINDY-MPC/blob/e1dfd9908b2b56af303ee9fb30a133aced4fd757/utils/sparsifyDynamics.m).
It solves the following problem

```math
\\argmin_{x} \\frac{1}{2} \\| Ax-b\\|_2 + \\rho \\|x\\|_2
```

with the additional constraint

```math
Expand All @@ -17,16 +19,20 @@ If the parameter `ρ > 0`, ridge regression will be performed using the normal e
regression problem.

# Fields

$(FIELDS)

# Example

```julia
opt = STLSQ()
opt = STLSQ(1e-1)
opt = STLSQ(1e-1, 1.0) # Set rho to 1.0
opt = STLSQ(Float32[1e-2; 1e-1])
```

## Note

This was formally `STRRidge` and has been renamed.
"""
struct STLSQ{T <: Union{Number, AbstractVector}, R <: Number} <:
Expand Down
2 changes: 2 additions & 0 deletions lib/DataDrivenSparse/src/algorithms/proximals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Proximal operator, which implements the soft thresholding operator.
```julia
sign(x) * max(abs(x) - λ, 0)
```

See [by Zheng et al., 2018](https://ieeexplore.ieee.org/document/8573778).
"""
struct SoftThreshold <: AbstractProximalOperator end;
Expand Down Expand Up @@ -52,6 +53,7 @@ Proximal operator, which implements the hard thresholding operator.
```julia
abs(x) > sqrt(2*λ) ? x : 0
```

See [by Zheng et al., 2018](https://ieeexplore.ieee.org/document/8573778).
"""
struct HardThreshold <: AbstractProximalOperator end;
Expand Down
4 changes: 3 additions & 1 deletion lib/DataDrivenSparse/src/commonsolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ function __sparse_regression(ps::InternalDataDrivenProblem{<:ImplicitOptimizer},
idx = ones(Bool, size(candidate_matrix, 2))

for i in axes(candidate_matrix, 1), j in axes(candidate_matrix, 2)

idx .= true
idx[j] = false
# We want only equations which are either dependent on the variable or on no other
Expand All @@ -72,7 +73,8 @@ function __sparse_regression(ps::InternalDataDrivenProblem{<:ImplicitOptimizer},

foreach(enumerate(eachcol(candidate_matrix))) do (i, idx)
# We enforce that one of the implicit variables is necessary for success
coeff, thresholds, iters = alg(X[idx, :], Y, options = options,
coeff, thresholds,
iters = alg(X[idx, :], Y, options = options,
necessary_idx = implicit_idx[idx, i])
opt_coefficients[i:i, idx] .= coeff
push!(opt_thresholds, thresholds)
Expand Down
6 changes: 4 additions & 2 deletions src/basis/build_function.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ function DataDrivenFunction(rhs, implicits, states, parameters, iv, controls,
_is_controlled = !isempty(controls)

if !eval_expression
f_oop, f_iip = build_function(rhs,
f_oop,
f_iip = build_function(rhs,
value.(implicits), value.(states), value.(parameters),
[value(iv)], value.(controls),
expression = Val{false})
else
ex_oop, ex_iip = build_function(rhs,
ex_oop,
ex_iip = build_function(rhs,
value.(implicits), value.(states),
value.(parameters),
[value(iv)], value.(controls),
Expand Down
Loading
Loading