Skip to content

Commit 73ebd41

Browse files
DOC: Add objects.rst, slim down README.rst
1 parent 61f828d commit 73ebd41

File tree

4 files changed

+160
-96
lines changed

4 files changed

+160
-96
lines changed

README.rst

Lines changed: 41 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -3,69 +3,53 @@ PySINDy
33

44
|BuildCI| |RTD| |PyPI| |Codecov| |JOSS1| |JOSS2| |DOI|
55

6-
**PySINDy** is a sparse regression package with several implementations for the
6+
**PySINDy** is a package for system identification, primarily revolving around the method of
77
Sparse Identification of Nonlinear Dynamical systems (SINDy) method introduced
88
in Brunton et al. (2016a).
9-
It also includes a variety of other methods from related literature.
10-
A comprehensive literature review is given in de Silva et al. (2020) and Kaptanoglu, de Silva et al. (2021).
9+
It also includes other methods from related literature.
1110

12-
System identification
13-
---------------------
14-
System identification refers to the process of leveraging measurement data to infer governing equations, in the form of dynamical systems, describing the data.
11+
*System identification* refers to the process of using measurement data to infer the governing dynamics.
1512
Once discovered, these equations can make predictions about future states, can inform control inputs, or can enable the theoretical study using analytical techniques.
16-
Dynamical systems are a flexible, well-studied class of mathematical objects for modeling systems evolving in time.
17-
SINDy is a model discovery method which uses *sparse regression* to infer nonlinear dynamical systems from measurement data.
1813
The resulting models are inherently *interpretable* and *generalizable*.
1914

20-
How it works
21-
^^^^^^^^^^^^
22-
Suppose, for some physical system of interest, we have measurements of state variables ``x(t)`` (a vector of length n) at different points in time. Examples of state variables include the position, velocity, or acceleration of objects; lift, drag, or angle of attack of aerodynamic objects; and concentrations of different chemical species. If we suspect that the system could be well-modeled by a dynamical system of the form
2315

24-
.. code-block:: text
25-
26-
x'(t) = f(x(t)),
27-
28-
then we can use SINDy to learn ``f(x)`` from the data (``x'(t)`` denotes the time derivative of ``x(t)``). Note that both ``f(x)`` and ``x(t)`` are typically vectors. The fundamental assumption SINDy employs is that each component of ``f(x)``, ``f_i(x)`` can be represented as a *sparse* linear combination of basis functions ``theta_j(x)``
29-
30-
.. code-block:: text
31-
32-
f_i(x) = theta_1(x) * xi_{1,i} + theta_2(x) * xi_{2,i} + ... + theta_k * xi{k,i}
16+
First Steps
17+
------------------
3318

34-
Concatenating all the objects into matrices (denoted with capitalized names) helps to simplify things.
35-
To this end we place all measurements of the state variables into a data matrix ``X`` (with a row per time measurement and a column per variable), the derivatives of the state variables into a matrix ``X'``, all basis functions evaluated at all points in time into a matrix ``Theta(X)`` (each basis function gets a column), and all coefficients into a third matrix ``Xi`` (one column per state variable).
36-
The approximation problem to be solved can then be compactly written as
37-
38-
.. code-block:: text
39-
40-
X' = Theta(X) * Xi.
19+
Installation
20+
^^^^^^^^^^^^^^
4121

42-
Each row of this matrix equation corresponds to one coordinate function of ``f(x)``.
43-
SINDy employs sparse regression techniques to find a solution ``Xi`` with sparse column vectors.
44-
For a more in-depth look at the mathematical foundations of SINDy, please see our `introduction to SINDy <https://pysindy.readthedocs.io/en/latest/examples/2_introduction_to_sindy/example.html>`__.
22+
The preferred way to install is with pip or conda e.g. ``pip install pysindy``.
23+
You may have to add the ``--user`` option.
24+
Pysindy also provides several extras, e.g. ``pip install pysindy[miosr]``:
4525

46-
Relation to PySINDy
47-
^^^^^^^^^^^^^^^^^^^
48-
The PySINDy package revolves around the ``SINDy`` class which consists of three primary components; one for each term in the above matrix approximation problem.
26+
cvxpy
27+
Convex optimizer ``SR3`` and subclasses
4928

50-
* ``differentiation_method``: computes ``X'``, though if derivatives are known or measured directly, they can be used instead
51-
* ``feature_library``: specifies the candidate basis functions to be used to construct ``Theta(X)``
52-
* ``optimizer``: implements a sparse regression method for solving for ``Xi``
29+
miosr
30+
Branch-and-bound optimizer for L0-constraint, ``MIOSR``
5331

54-
Once a ``SINDy`` object has been created it must be fit to measurement data, similar to a ``scikit-learn`` model.
55-
It can then be used to predict derivatives given new measurements, evolve novel initial conditions forward in time, and more.
32+
sbr
33+
Bayesian regression optimizer yielding posteriors, ``SBR``.
5634

5735
Example
58-
^^^^^^^
36+
^^^^^^^^^^^
5937
Suppose we have measurements of the position of a particle obeying the following dynamical system at different points in time
6038

61-
.. code-block:: text
39+
.. math::
6240
63-
x' = -2x
64-
y' = y
41+
x' &= -2 x \\
42+
y' &= y
6543
66-
Note that this system of differential equations decouples into two differential equations whose solutions are simply ``x(t) = x_0 * exp(-2 * t)`` and ``y(t) = y_0 * exp(t)``, where ``x_0 = x(0)`` and ``y_0 = y(0)`` are the initial conditions.
44+
Note that this system of differential equations decouples into two differential equations whose solutions are simply
6745

68-
Using the initial conditions ``x_0 = 3`` and ``y_0 = 0.5``, we construct the data matrix ``X``.
46+
.. math::
47+
48+
x(t) &= x_0 * exp(-2 * t) \\
49+
y(t) &= y_0 * exp(t)
50+
51+
This example uses the initial conditions ``x_0 = 3`` and ``y_0 = 0.5``.
52+
It then fits and prints the discovered model
6953

7054
.. code-block:: python
7155
@@ -77,69 +61,31 @@ Using the initial conditions ``x_0 = 3`` and ``y_0 = 0.5``, we construct the dat
7761
y = 0.5 * np.exp(t)
7862
X = np.stack((x, y), axis=-1) # First column is x, second is y
7963
80-
To instantiate a ``SINDy`` object with the default differentiation method, feature library, and optimizer and then fit it to the data, we invoke
81-
82-
.. code-block:: python
83-
84-
model = ps.SINDy(feature_names=["x", "y"])
85-
model.fit(X, t=t)
86-
87-
We use the ``feature_names`` argument so that the model prints out the correct labels for ``x`` and ``y``. We can inspect the governing equations discovered by the model and check whether they seem reasonable with the ``print`` function.
88-
89-
.. code-block:: python
90-
64+
model = ps.SINDy()
65+
model.fit(X, t=t, feature_names=["x", "y"])
9166
model.print()
9267
93-
which prints the following
68+
which correctly results in
9469

9570
.. code-block:: text
9671
9772
x' = -2.000 x
9873
y' = 1.000 y
9974
100-
PySINDy provides numerous other features not shown here. We recommend the `feature overview <https://pysindy.readthedocs.io/en/latest/examples/1_feature_overview/example.html>`__ section of the documentation for a more exhaustive summary of additional features.
101-
102-
Installation
103-
------------
104-
105-
The preferred way to install is with pip or conda e.g. ``pip install pysindy``.
106-
You may have to add ``--user`` option.
107-
Pysindy also provides several extras:
75+
PySINDy provides numerous other features not shown here. We have a variety of tutorials and examples, starting with
76+
`feature overview <https://pysindy.readthedocs.io/en/latest/examples/1_feature_overview/example.html>`_.
10877

109-
cvxpy
110-
Convex optimizer ``SR3`` and subclasses
11178

112-
miosr
113-
Branch-and-bound optimizer for L0-constraint, ``MIOSR``
114-
115-
sbr
116-
Bayesian regression optimizer yielding posteriors, ``SBR``.
117-
118-
119-
Documentation
79+
Getting Help
12080
-------------
121-
The documentation site for PySINDy can be found `here <https://pysindy.readthedocs.io/en/latest/>`__.
122-
There are numerous `examples <https://pysindy.readthedocs.io/en/latest/examples/index.html>`_ of PySINDy in action to help you get started.
123-
Examples are also available as `Jupyter notebooks <https://github.com/dynamicslab/pysindy/tree/master/examples>`__.
124-
A video overview of PySINDy can be found on `Youtube <https://www.youtube.com/watch?v=DvbbXX8Bd90>`__.
125-
We have also created a `video playlist <https://www.youtube.com/playlist?list=PLN90bHJU-JLoOfEk0KyBs2qLTV7OkMZ25>`__ with practical PySINDy tips.
126-
127-
If something is unclear, please open an issue. To discuss your particular dynamics problem, open a discussion. Make sure to format your example as python code in github!
128-
129-
PySINDy implements a lot of advanced functionality that may be overwhelming for new users or folks who are unfamiliar with these methods. Below (see here if image does not render https://github.com/dynamicslab/pysindy/blob/master/docs/JOSS2/Fig3.png), we provide a helpful flowchart for figuring out which methods to use, given the characteristics of your dataset:
130-
131-
.. image:: https://github.com/dynamicslab/pysindy/blob/master/docs/JOSS2/Fig3.png
132-
133-
This flow chart summarizes how ``PySINDy`` users can start with a dataset and systematically choose the proper candidate library and sparse regression optimizer that are tailored for a specific scientific task. The ``GeneralizedLibrary`` class allows for tensoring, concatenating, and otherwise combining many different candidate libraries.
134-
135-
Contributions:
136-
-----------------------------
137-
See `Contributor guide <https://pysindy.readthedocs.io/en/latest/contributing.html>`_.
138-
13981

140-
Citing PySINDy
141-
-----------------
142-
See `Academic use <https://pysindy.readthedocs.io/en/latest/academic.html>`_.
82+
* If you have a **question** or find a **bug**, please open an `issue <https://github.com/dynamicslab/pysindy/issues>`_ on github.
83+
* The **documentation** site for PySINDy can be found `here <https://pysindy.readthedocs.io/en/latest/>`__.
84+
A video overview of PySINDy can be found on `Youtube <https://www.youtube.com/watch?v=DvbbXX8Bd90>`__.
85+
We have also created a `video playlist <https://www.youtube.com/playlist?list=PLN90bHJU-JLoOfEk0KyBs2qLTV7OkMZ25>`__ with practical PySINDy tips.
86+
* To understand more about the **types of objects** in pysindy, see the `object model <https://pysindy.readthedocs.io/en/latest/objects>`_.
87+
* If you want to fix a problem, add a feature, or share an example, check the `**Contributor** Guide <https://pysindy.readthedocs.io/en/latest/contributing.html>`_.
88+
* If you are using pysindy in **academic** work, please see `Academic Use <https://pysindy.readthedocs.io/en/latest/academic.html>`_ for recommendations, including **citations**.
14389

14490

14591
Related packages

docs/index.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@
33

44
.. toctree::
55
:maxdepth: 1
6+
:hidden:
67
:caption: User Guide
78

89
API Documentation <api/pysindy>
910
Examples <examples/index>
1011
Practical tips <tips>
1112
Contributing <contributing>
1213
Using pysindy in academia <academic>
14+
Object Model <objects>
1315

1416
.. toctree::
1517
:maxdepth: 1
18+
:hidden:
1619
:caption: Useful links
1720

18-
1921
PySINDy @ PyPI <https://pypi.org/project/PySINDy/>
2022
Issue Tracker <https://github.com/dynamicslab/pysindy/issues>

docs/objects.rst

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
PySINDy Object Model
2+
========================
3+
This document describes the main types of objects in pysindy
4+
and how users tend to interact with them.
5+
It then proceeds to summarize the problems and planned changes to the type system,
6+
as discussed in issues like
7+
`this one <https://github.com/dynamicslab/pysindy/issues/351>`_.
8+
It is most useful for people who want to implement their own variant of SINDy
9+
within the pysindy package.
10+
11+
Current typing system
12+
----------------------------
13+
The PySINDy package revolves around the abstract base class ``_BaseSINDy`` which represents
14+
the problem of fitting a dynamical system :math:`X' = \Xi^T \Theta(X)`.
15+
It implements the basics of printing the discovered system of equations and
16+
fitting the shape of inputs and outputs.
17+
For example, it contains methods like ``equations()``, ``print()``, and ``_fit_shape()``.
18+
Different subclasses handle how that fitting actually occurs:
19+
As the only current concrete subclass, ``SINDy`` objects follow the traditional approach, comprising a
20+
21+
* ``differentiation_method: BaseDifferentiation``: computes :math:`X'`.
22+
Subclasses often accept an ``axis`` and ``order`` argument, and are callable objects.
23+
When creating new differentiation methods, add them to the |derivative|_.
24+
* ``feature_library: BaseFeatureLibrary``: specifies the candidate basis functions to be used to construct :math:`\Theta(X)`.
25+
Most significantly for the end user, ``fit()`` determines the number and string format
26+
of the feature library, as applied to the input variables.
27+
You can see these with ``BaseFeatureLibrary.get_feature_names()`` or ``BaseFeatureLibrary.n_features_out_``.
28+
One challenge with the straight-pipeline approach is that constraints must be manually constructed as arrays,
29+
and require knowing the order of the features, which in turn requires the feature library to be fit.
30+
There is no harm, however, in fitting the feature library on the data before fitting ``SINDy``,
31+
even though the latter will refit the feature library.
32+
``transform()`` is used to actually calculate the feature values on input data.
33+
* ``optimizer: BaseOptimizer``: implements a sparse regression method for solving for :math:`\Xi`.
34+
These share a common ``fit()`` method, with different implementations going in ``_reduce()``.
35+
Most notably, they share a ``history_`` of coefficient values and a ``coef_`` array of the final coefficients.
36+
When subclassing ``BaseOptimizer``, be sure to note whether your approach can be unbiased,
37+
and if not, raise an error if set to ``True``.
38+
39+
40+
.. |derivative| replace:: ``derivative`` package
41+
.. _derivative: https://derivative.readthedocs.io/en/latest/
42+
43+
Once a ``SINDy`` object has been created it must be fit to measurement data, similar to a ``scikit-learn`` model.
44+
It can then be used to predict derivatives given new measurements in ``predict()``
45+
as well as evolve novel initial conditions forward in time using ``simulate()``.
46+
It can also ``score()`` itself. Take care, however, as there are different metrics
47+
for a SINDy model (`issue 1`_, `issue 2`_).
48+
49+
.. _issue 1: https://github.com/dynamicslab/pysindy/issues/372
50+
51+
.. _issue 2: https://github.com/scikit-learn/scikit-learn/issues/31360
52+
53+
54+
Problems
55+
---------------------
56+
.. admonition:: A good rule
57+
58+
Type compatibility should equate to mathematical compatibility
59+
60+
While the single base class ``SINDy`` worked for a while, it ran into problems as different innovations
61+
were added as either differentiation methods, feature libraries, or optimizers,
62+
but not as new types.
63+
Oftentimes the innovations were only compatible with correct decisions on other objects in the SINDy model,
64+
e.g. trapping SINDy is implemented as a ``TrappingSR3`` optimizer, but is only mathematically sensible with a quadratic Polynomial library.
65+
At the same time, the Polynomial library type is not parameterized by polynomial order,
66+
which is just one of the changes that would need to exist in order for the type system to enforce mathematical compatibility.
67+
68+
Similar problems exist in Weak SINDy and SINDy-PI, whose implementations are deeply coupled.
69+
70+
Future type system changes
71+
-----------------------------
72+
Currently weak SINDy is implemented through the ``WeakPDELibrary`` in a basic SINDy model.
73+
However, as it eschews derivative calculation, ``WeakSINDy`` will soon exist as a subclass of ``_BaseSINDy``
74+
for fitting continuous dynamics using the integral form.
75+
76+
Similarly, discrete SINDy, which does not use a differentiation method, will become a subclass of ``_BaseSINDy``
77+
rather than an argument to the ``SINDy`` initialization.
78+
79+
SINDy-PI is a unique problem in that it represents the problem of fitting a dynamical system,
80+
as does ``_BaseSINDy``,
81+
but produces a set of possible coefficient matrices with no ability to choose from them.
82+
Moreover, the equations it attempts to discover are implicit and do not create predictions in a uniform way.
83+
This means that ``predict()``, ``simulate()``, and ``equations()`` do not work.
84+
SINDy-PI is currently implemented across the ``PDELibrary``, ``WeakPDELibrary`` and ``SINDyPIOptimizer``,
85+
but will eventually become its own class that interacts with ``SINDy``, ``WeakSINDy``, Discrete SINDy,
86+
and component objects in a unique way.
87+
88+
``EnsembleOptimizer`` and ``SBR`` are two different optimizers that result in a distribution of coefficients.
89+
The former wraps another optimizer, however it should not wrap ``SBR`` or another ``EnsembleOptimizer``.
90+
This reflects a fundamental difference in types: ``RandomVariableOptimizers`` whose coefficients are understaood to be random variables
91+
and ``DeterministicOptimizers`` whose coefficients are deterministic.
92+
Moreover, post-analysis of random variable optimizers is ad-hoc;
93+
users must access the underlying numpy arrays (``EnsembleOptimizer``)
94+
or numpyro random variables (``SBR``) in order to visualize the distributions.
95+
While that is a smaller problem, it suggests a unified API would support better comparison of these approaches.
96+
97+
98+
Trapping SINDy, as mentioned, requires some spooky action at a distance.
99+
It may become a factory function which chooses the optimizer and feature library for the user,
100+
depending on whether the user wants weak or traditional SINDy.
101+
102+
Differentiation began with ``FiniteDifference``, but quickly moved to methods that
103+
both smooth and differentiate.
104+
For a while pysindy did not use the smooth coordinates, only the smoothed derivatives.
105+
For backwards compatibility, the smoothed coordinates were attached
106+
to the ``BaseDifferentiation`` object, rather than returned.
107+
Using differentiation for PDEs adds additional complexity.
108+
Some differentation/smoothing methods assume a single order of smoothness,
109+
which makes them unsuitable for most PDEs.
110+
Smoothing that only smoothes in one axis as a time does not result in consistent
111+
trajectories when smoothed along different axes.
112+
Moreover, most existing implementations are defined in the ``derivative`` package.
113+
Ideally, ``pysindy`` gets out of the business of derivative implementations,
114+
merely specifying (and correctly using) an API that treats differentiation and smoothing
115+
as two aspects of applying assumptions to a random process.

examples/README.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ This directory showcases examples of PySINDy in action.
55
Some are copied from another repository that contains dependency information and
66
potentially a greater description.
77

8+
Tutorials in the pysindy repo are also available as `Jupyter notebooks <https://github.com/dynamicslab/pysindy/tree/master/examples>`_.
89
Some notebooks require substantial computing resources.
910

1011
`Feature overview <./1_feature_overview/example.ipynb>`_

0 commit comments

Comments
 (0)