Source code for pysindy.deeptime.deeptime

"""
`Deeptime <https://deeptime-ml.github.io/>`_ wrapper interface for PySINDy.
"""
from sklearn import __version__
from sklearn.pipeline import Pipeline
from sklearn.utils.validation import check_is_fitted

from ..pysindy import SINDy
from ..utils import SampleConcatter


[docs]class SINDyEstimator(SINDy): """ Implementation of SINDy conforming to the API of a Deeptime `Estimator \ <https://deeptime-ml.github.io/api/generated/deeptime.base.Estimator.html>`_. Parameters ---------- optimizer : optimizer object, optional Optimization method used to fit the SINDy model. This must be an object extending :class:`pysindy.optimizers.BaseOptimizer`. Default is sequentially thresholded least squares with a threshold of 0.1. feature_library : feature library object, optional Feature library object used to specify candidate right-hand side features. This must be an object extending the :class:`pysindy.feature_library.base.BaseFeatureLibrary`. Default is polynomial features of degree 2. differentiation_method : differentiation object, optional Method for differentiating the data. This must be an object extending the :class:`pysindy.differentiation_methods.base.BaseDifferentiation` class. Default is centered difference. feature_names : list of string, length n_input_features, optional Names for the input features (e.g. ``['x', 'y', 'z']``). If None, will use ``['x0', 'x1', ...]``. t_default : float, optional (default 1) Default value for the time step. discrete_time : boolean, optional (default False) If True, dynamical system is treated as a map. Rather than predicting derivatives, the right hand side functions step the system forward by one time step. If False, dynamical system is assumed to be a flow (right-hand side functions predict continuous time derivatives). Attributes ---------- model : sklearn.multioutput.MultiOutputRegressor object The fitted SINDy model. n_input_features_ : int The total number of input features. n_output_features_ : int The total number of output features. This number is a function of ``self.n_input_features`` and the feature library being used. """ def __init__( self, optimizer=None, feature_library=None, differentiation_method=None, feature_names=None, t_default=1, discrete_time=False, ): super(SINDyEstimator, self).__init__( optimizer=optimizer, feature_library=feature_library, differentiation_method=differentiation_method, feature_names=feature_names, t_default=t_default, discrete_time=discrete_time, ) self._model = None
[docs] def fit(self, x, **kwargs): """ Fit the SINDyEstimator to data, learning a dynamical systems model for the data. Parameters ---------- x: array-like or list of array-like, shape (n_samples, n_input_features) Training data. If training data contains multiple trajectories, x should be a list containing data for each trajectory. Individual trajectories may contain different numbers of samples. **kwargs: dict, optional Optional keyword arguments to pass to :meth:`fit` method. Returns ------- self: fitted :class:`SINDyEstimator` instance """ super(SINDyEstimator, self).fit(x, **kwargs) self._model = SINDyModel( feature_library=self.model.steps[0][1], optimizer=self.model.steps[-1][1], feature_names=self.feature_names, t_default=self.t_default, discrete_time=self.discrete_time, n_control_features_=self.n_control_features_, ) return self
[docs] def fetch_model(self): """ Yields the estimated model. Can be none if :meth:`fit` was not called. Returns ------- model: :class:`SINDyModel` or None The estimated SINDy model or none """ return self._model
@property def has_model(self): """Property reporting whether this estimator contains an estimated model. This assumes that the model is initialized with ``None`` otherwise. :type: bool """ return self._model is not None
[docs]class SINDyModel(SINDy): """ Implementation of SINDy conforming to the API of a Deeptime `Model <https://deeptime-ml.github.io/api/generated/deeptime.base.Model.html>`_. The model is represented as a Scikit-learn pipeline object with three steps: 1. Map the raw input data to nonlinear features according to the selected ``feature_library`` 2. Reshape the data from input shape to an optimization problem 3. Multiply the nonlinear features with a coefficient matrix encapuslated in ``optimizer``. This class expects the feature library and optimizer to already be fit with a :class:`SINDyEstimator`. It is best to instantiate a :class:`SINDyModel` object via the :meth:`SINDyEstimator.fetch_model()` rather than calling the :class:`SINDyModel` constructor directly. Parameters ---------- optimizer : optimizer object Optimization method used to fit the SINDy model. This must be an (already fit) object extending :class:`pysindy.optimizers.BaseOptimizer`. feature_library : feature library object Feature library object used to specify candidate right-hand side features. This must be an (already fit) object extending :class:`pysindy.feature_library.BaseFeatureLibrary`. differentiation_method : differentiation object Method for differentiating the data. This must be an object extending :class:`pysindy.differentiation_methods.BaseDifferentiation`. Default is centered difference. feature_names : list of string, length n_input_features, optional Names for the input features (e.g. ``['x', 'y', 'z']``). If None, will use ``['x0', 'x1', ...]``. t_default : float, optional (default 1) Default value for the time step. discrete_time : boolean, optional (default False) If True, dynamical system is treated as a map. Rather than predicting derivatives, the right hand side functions step the system forward by one time step. If False, dynamical system is assumed to be a flow (right-hand side functions predict continuous time derivatives). Attributes ---------- model : sklearn.multioutput.MultiOutputRegressor object The fitted SINDy model. n_input_features_ : int The total number of input features. n_output_features_ : int The total number of output features. This number is a function of ``self.n_input_features`` and the feature library being used. """ def __init__( self, feature_library, optimizer, feature_names=None, t_default=1, discrete_time=False, n_control_features_=0, ): super(SINDyModel, self).__init__( feature_library=feature_library, optimizer=optimizer, feature_names=feature_names, t_default=t_default, discrete_time=discrete_time, ) self.n_control_features_ = n_control_features_ check_is_fitted(feature_library) check_is_fitted(optimizer) steps = [ ("features", feature_library), ("shaping", SampleConcatter()), ("model", optimizer), ] self.model = Pipeline(steps) if float(__version__[:3]) >= 1.0: self.n_features_in_ = self.model.steps[0][1].n_features_in_ else: self.n_input_features_ = self.model.steps[0][1].n_input_features_ self.n_output_features_ = self.model.steps[0][1].n_output_features_
[docs] def copy(self): """Makes a deep copy of this model. Returns ------- copy: :class:`SINDyModel` A new copy of this model. """ import copy return copy.deepcopy(self)