From ff13eefbf44efdc055a00c3bfa095cbeadb435e0 Mon Sep 17 00:00:00 2001 From: pogudingleb Date: Wed, 8 Nov 2023 21:33:14 +0100 Subject: [PATCH 1/4] fixing checks in the docs --- docs/make.jl | 2 +- docs/pages.jl | 2 +- docs/src/utils/ode.md | 7 +++++++ src/ODE.jl | 3 +-- 4 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 docs/src/utils/ode.md diff --git a/docs/make.jl b/docs/make.jl index e60577c55..47f111f43 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -18,7 +18,7 @@ makedocs( canonical = "https://docs.sciml.ai/StructuralIdentifiability/stable/", ), pages = pages, - checkdocs = :none, + checkdocs = :exports, ) deploydocs(repo = "github.com/SciML/StructuralIdentifiability.jl.git"; push_preview = true) diff --git a/docs/pages.jl b/docs/pages.jl index defedf292..2b809b7d2 100644 --- a/docs/pages.jl +++ b/docs/pages.jl @@ -10,7 +10,7 @@ pages = [ "Local Identifiability Tools" => "utils/local_identifiability.md", "Global Identifiability Tools" => "utils/global_identifiability.md", "Elimination" => "utils/elimination.md", - # "ODE Tools" => "utils/ode.md", + "ODE Tools" => "utils/ode.md", "Power Series Tools" => "utils/power_series_utils.md", "Primality Checks" => "utils/primality.md", "Wronskian Tools" => "utils/wronskian.md", diff --git a/docs/src/utils/ode.md b/docs/src/utils/ode.md new file mode 100644 index 000000000..e40f62996 --- /dev/null +++ b/docs/src/utils/ode.md @@ -0,0 +1,7 @@ +# Functions to work with the ODE structure + +```@autodocs +Modules = [StructuralIdentifiability] +Pages = ["ODE.jl", "submodels.jl"] +Order = [:function] +``` diff --git a/src/ODE.jl b/src/ODE.jl index 67193547c..fc05b91d9 100644 --- a/src/ODE.jl +++ b/src/ODE.jl @@ -1,4 +1,3 @@ -# P is the type of polynomials in the rhs of the ODE system """ The main structure that represents input ODE system. @@ -6,7 +5,7 @@ Stores information about states (`x_vars`), outputs (`y_vars`), inputs (`u_vars` This structure is constructed via `@ODEmodel` macro. """ -struct ODE{P} +struct ODE{P} # P is the type of polynomials in the rhs of the ODE system poly_ring::MPolyRing x_vars::Array{P, 1} y_vars::Array{P, 1} From 5db210a4433b6fae8cc69f89f309ecb0bd1bbca9 Mon Sep 17 00:00:00 2001 From: pogudingleb Date: Wed, 8 Nov 2023 23:18:43 +0100 Subject: [PATCH 2/4] Adding discrete time tutorial --- docs/pages.jl | 1 + docs/src/assets/Project.toml | 3 +- docs/src/tutorials/discrete_time.md | 71 +++++++++++++++++++++++++++ docs/src/tutorials/identifiability.md | 2 +- 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 docs/src/tutorials/discrete_time.md diff --git a/docs/pages.jl b/docs/pages.jl index 2b809b7d2..a71718123 100644 --- a/docs/pages.jl +++ b/docs/pages.jl @@ -4,6 +4,7 @@ pages = [ "tutorials/creating_ode.md", "tutorials/identifiability.md", "tutorials/identifiable_functions.md", + "tutorials/discrete_time.md", ], "Basics" => Any["input/input.md", "identifiability/identifiability.md"], "Library" => Any[ diff --git a/docs/src/assets/Project.toml b/docs/src/assets/Project.toml index 6998d3954..e4c519b6b 100644 --- a/docs/src/assets/Project.toml +++ b/docs/src/assets/Project.toml @@ -6,5 +6,6 @@ StructuralIdentifiability = "220ca800-aa68-49bb-acd8-6037fa93a544" [compat] BenchmarkTools = "1.3" -Documenter = "0.27" +Documenter = "0.27, 1" ModelingToolkit = "8.34" +StructuralIdentifiability = "0.4" diff --git a/docs/src/tutorials/discrete_time.md b/docs/src/tutorials/discrete_time.md new file mode 100644 index 000000000..21b315bd9 --- /dev/null +++ b/docs/src/tutorials/discrete_time.md @@ -0,0 +1,71 @@ +# Identifiability of Discrete-Time Models (Local) + +Now we consider a discrete-time model in the state-space form + +$\begin{cases} +\mathbf{x}(t + 1) = \mathbf{f}(\mathbf{x}(t), \mathbf{p}, \mathbf{u}(t)),\\ +\mathbf{y}(t) = \mathbf{g}(\mathbf{x}(t), \mathbf{p}, \mathbf{u(t)}), +\end{cases}$ + +where $\mathbf{x}(t), \mathbf{y}(t)$, and $\mathbf{u}(t)$ are time-dependent states, outputs, and inputs, respectively, +and $\mathbf{p}$ are scalar parameters. +As in the ODE case, we will call that a parameter or a states (or a function of them) is **identifiable** if its value can be recovered from +time series for inputs and outputs (in the generic case, see Definition 3 in [^1] for details). +Again, we will distinguish two types of identifiability + + - **local** identifiability: the value can be recovered up to finitely many options; + + - **global** identifiability: the value can be recovered uniquely. + +Currently, `StructuralIdentifiability.jl` allows to assess only local identifiability for discrete-time models, +and below we will describe how this can be done. +As a running example, we will use the following discrete version of the [SIR](https://en.wikipedia.org/wiki/Compartmental_models_in_epidemiology#The_SIR_model) model: +$\begin{cases} + S(t + 1) = S(t) - \beta S(t) I(t),\\ + I(t + 1) = I(t) + \beta S(t) I(t) - \alpha I(t),\\ + R(t + 1) = R(t) + \alpha I(t),\\ + y(t) = I(t), +\end{cases}$ + +where the observable is `I`, the number of infected people. +We start with creating a system as a `DiscreteSystem` from `ModelingToolkit`: +```@example discrete +using ModelingToolkit +using StructuralIdentifiability + +@parameters α β +@variables t S(t) I(t) R(t) y(t) +D = Difference(t; dt = 1.0) + +eqs = [D(S) ~ S - β * S * I, D(I) ~ I + β * S * I - α * I, D(R) ~ R + α * I] +@named sir = DiscreteSystem(eqs) +``` + +Once the model is defined, we can assess identifiability by providing the formula for the observable: +```@example discrete +assess_local_identifiability(sir; measured_quantities = [y ~ I]) +``` +For each parameter or state, the value in the returned dictionary is `true` (`1`) if the parameter is locally identifiable and `false` (`0`) otherwise. +We see that `R(t)` is not identifiable, which makes sense: it does not affect the dynamics of the observable in any way. + +In principle, it is not required to give a name to the observable, so one can write this shorter +```@example discrete +assess_local_identifiability(sir; measured_quantities = [I]) +``` + +The `assess_local_identifiability` function has two important keyword arguments: + +* `funcs_to_check` is a list of functions for which one want to assess identifiability, for example, the following code + will check if `β * S` is locally identifiable. + +```@example discrete +assess_local_identifiability(sir; measured_quantities = [I], funcs_to_check = [β * S]) +``` + +* `p` is the probability of correctness (default value `0.99`, i.e., 99%). The underlying algorithm is a Monte-Carlo algorithm, so in + principle it may produce incorrect result but the probability of correctness of the returned result is guaranteed to be at least `p` + (in fact, the employed bounds are quite conservative, so in practice incorrect result is almost never produced). + +The implementation is based on a version of the observability rank criterion and will be described in a forthcoming paper. + +[^1]: > S. Nõmm, C. Moog, [*Identifiability of discrete-time nonlinear systems*](https://doi.org/10.1016/S1474-6670(17)31245-4), IFAC Proceedings Volumes, 2004. diff --git a/docs/src/tutorials/identifiability.md b/docs/src/tutorials/identifiability.md index 4d6339adf..242b377c6 100644 --- a/docs/src/tutorials/identifiability.md +++ b/docs/src/tutorials/identifiability.md @@ -15,7 +15,7 @@ Typically, two types of identifiability are distinguished - **local** identifiability: the value can be recovered up to finitely many options; - - **global** identifiability: the value can be recoevered uniquely. + - **global** identifiability: the value can be recovered uniquely. Note that in the case of states, term **observability** it typically used. We will use **identifiability** for both states and parameters for brevity and uniformity. From 19c6d9fdcc2bb29871b3bf71812f73ae7ef7693d Mon Sep 17 00:00:00 2001 From: pogudingleb Date: Wed, 8 Nov 2023 23:22:05 +0100 Subject: [PATCH 3/4] formatter --- docs/src/tutorials/discrete_time.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/src/tutorials/discrete_time.md b/docs/src/tutorials/discrete_time.md index 21b315bd9..b2f393624 100644 --- a/docs/src/tutorials/discrete_time.md +++ b/docs/src/tutorials/discrete_time.md @@ -1,6 +1,6 @@ # Identifiability of Discrete-Time Models (Local) -Now we consider a discrete-time model in the state-space form +Now we consider a discrete-time model in the state-space form $\begin{cases} \mathbf{x}(t + 1) = \mathbf{f}(\mathbf{x}(t), \mathbf{p}, \mathbf{u}(t)),\\ @@ -17,18 +17,19 @@ Again, we will distinguish two types of identifiability - **global** identifiability: the value can be recovered uniquely. -Currently, `StructuralIdentifiability.jl` allows to assess only local identifiability for discrete-time models, +Currently, `StructuralIdentifiability.jl` allows to assess only local identifiability for discrete-time models, and below we will describe how this can be done. As a running example, we will use the following discrete version of the [SIR](https://en.wikipedia.org/wiki/Compartmental_models_in_epidemiology#The_SIR_model) model: $\begin{cases} - S(t + 1) = S(t) - \beta S(t) I(t),\\ - I(t + 1) = I(t) + \beta S(t) I(t) - \alpha I(t),\\ - R(t + 1) = R(t) + \alpha I(t),\\ - y(t) = I(t), +S(t + 1) = S(t) - \beta S(t) I(t),\\ +I(t + 1) = I(t) + \beta S(t) I(t) - \alpha I(t),\\ +R(t + 1) = R(t) + \alpha I(t),\\ +y(t) = I(t), \end{cases}$ where the observable is `I`, the number of infected people. We start with creating a system as a `DiscreteSystem` from `ModelingToolkit`: + ```@example discrete using ModelingToolkit using StructuralIdentifiability @@ -42,29 +43,32 @@ eqs = [D(S) ~ S - β * S * I, D(I) ~ I + β * S * I - α * I, D(R) ~ R + α * I] ``` Once the model is defined, we can assess identifiability by providing the formula for the observable: + ```@example discrete assess_local_identifiability(sir; measured_quantities = [y ~ I]) ``` + For each parameter or state, the value in the returned dictionary is `true` (`1`) if the parameter is locally identifiable and `false` (`0`) otherwise. We see that `R(t)` is not identifiable, which makes sense: it does not affect the dynamics of the observable in any way. In principle, it is not required to give a name to the observable, so one can write this shorter + ```@example discrete assess_local_identifiability(sir; measured_quantities = [I]) ``` The `assess_local_identifiability` function has two important keyword arguments: -* `funcs_to_check` is a list of functions for which one want to assess identifiability, for example, the following code - will check if `β * S` is locally identifiable. + - `funcs_to_check` is a list of functions for which one want to assess identifiability, for example, the following code + will check if `β * S` is locally identifiable. ```@example discrete assess_local_identifiability(sir; measured_quantities = [I], funcs_to_check = [β * S]) ``` -* `p` is the probability of correctness (default value `0.99`, i.e., 99%). The underlying algorithm is a Monte-Carlo algorithm, so in - principle it may produce incorrect result but the probability of correctness of the returned result is guaranteed to be at least `p` - (in fact, the employed bounds are quite conservative, so in practice incorrect result is almost never produced). + - `p` is the probability of correctness (default value `0.99`, i.e., 99%). The underlying algorithm is a Monte-Carlo algorithm, so in + principle it may produce incorrect result but the probability of correctness of the returned result is guaranteed to be at least `p` + (in fact, the employed bounds are quite conservative, so in practice incorrect result is almost never produced). The implementation is based on a version of the observability rank criterion and will be described in a forthcoming paper. From 9797a466fea09285f50d6facc2069680597d4f2c Mon Sep 17 00:00:00 2001 From: pogudingleb Date: Wed, 8 Nov 2023 23:23:42 +0100 Subject: [PATCH 4/4] spacing --- docs/src/tutorials/discrete_time.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/tutorials/discrete_time.md b/docs/src/tutorials/discrete_time.md index b2f393624..4c160a079 100644 --- a/docs/src/tutorials/discrete_time.md +++ b/docs/src/tutorials/discrete_time.md @@ -20,6 +20,7 @@ Again, we will distinguish two types of identifiability Currently, `StructuralIdentifiability.jl` allows to assess only local identifiability for discrete-time models, and below we will describe how this can be done. As a running example, we will use the following discrete version of the [SIR](https://en.wikipedia.org/wiki/Compartmental_models_in_epidemiology#The_SIR_model) model: + $\begin{cases} S(t + 1) = S(t) - \beta S(t) I(t),\\ I(t + 1) = I(t) + \beta S(t) I(t) - \alpha I(t),\\