diff --git a/autokoopman/autokoopman.py b/autokoopman/autokoopman.py index 9a210cb..371d3cf 100644 --- a/autokoopman/autokoopman.py +++ b/autokoopman/autokoopman.py @@ -5,7 +5,7 @@ import numpy as np -import autokoopman.core.observables as kobs +import autokoopman.observable as kobs from autokoopman.core.trajectory import ( TrajectoriesData, UniformTimeTrajectoriesData, @@ -24,7 +24,7 @@ from autokoopman.tuner.gridsearch import GridSearchTuner from autokoopman.tuner.montecarlo import MonteCarloTuner from autokoopman.tuner.bayesianopt import BayesianOptTuner -from autokoopman.core.observables import KoopmanObservable +from autokoopman.observable.observables import KoopmanObservable from autokoopman.core.format import hide_prints __all__ = ["auto_koopman"] diff --git a/autokoopman/observable/__init__.py b/autokoopman/observable/__init__.py new file mode 100644 index 0000000..f39f9e6 --- /dev/null +++ b/autokoopman/observable/__init__.py @@ -0,0 +1,2 @@ +from .observables import * +from .rff import * \ No newline at end of file diff --git a/autokoopman/core/observables.py b/autokoopman/observable/observables.py similarity index 77% rename from autokoopman/core/observables.py rename to autokoopman/observable/observables.py index ff179a8..cf9a89b 100644 --- a/autokoopman/core/observables.py +++ b/autokoopman/observable/observables.py @@ -4,8 +4,6 @@ import numpy as np import sympy as sp # type: ignore -from scipy.stats import cauchy, laplace - class KoopmanObservable(abc.ABC): """ @@ -163,51 +161,3 @@ def __init__(self, dimension, degree) -> None: def obs_fcn(self, X: np.ndarray) -> np.ndarray: return self.poly.transform(np.atleast_2d(X)).T - - -class RFFObservable(KoopmanObservable): - def __init__(self, dimension, num_features, gamma, metric="rbf"): - super(RFFObservable, self).__init__() - self.gamma = gamma - self.dimension = dimension - self.metric = metric - self.D = num_features - # Generate D iid samples from p(w) - if self.metric == "rbf": - self.w = np.sqrt(2 * self.gamma) * np.random.normal( - size=(self.D, self.dimension) - ) - elif self.metric == "laplace": - self.w = cauchy.rvs(scale=self.gamma, size=(self.D, self.dimension)) - # Generate D iid samples from Uniform(0,2*pi) - self.u = 2 * np.pi * np.random.rand(self.D) - - def obs_fcn(self, X: np.ndarray) -> np.ndarray: - # modification... - if len(X.shape) == 1: - x = np.atleast_2d(X.flatten()).T - else: - x = X.T - w = self.w.T - u = self.u[np.newaxis, :].T - s = np.sqrt(2 / self.D) - Z = s * np.cos(x.T @ w + u.T) - return Z.T - - def obs_grad(self, X: np.ndarray) -> np.ndarray: - if len(X.shape) == 1: - x = np.atleast_2d(X.flatten()).T - else: - x = X.T - x = np.atleast_2d(X.flatten()).T - w = self.w.T - u = self.u[np.newaxis, :].T - s = np.sqrt(2 / self.D) - # TODO: make this sparse? - Z = -s * np.diag(np.sin(u + w.T @ x).flatten()) @ w.T - return Z - - def compute_kernel(self, X: np.ndarray) -> np.ndarray: - Z = self.transform(X) - K = Z.dot(Z.T) - return K diff --git a/autokoopman/observable/rff.py b/autokoopman/observable/rff.py new file mode 100644 index 0000000..19f4613 --- /dev/null +++ b/autokoopman/observable/rff.py @@ -0,0 +1,52 @@ +import numpy as np +from scipy.stats import cauchy, laplace + +from .observables import KoopmanObservable + + +class RFFObservable(KoopmanObservable): + def __init__(self, dimension, num_features, gamma, metric="rbf"): + super(RFFObservable, self).__init__() + self.gamma = gamma + self.dimension = dimension + self.metric = metric + self.D = num_features + # Generate D iid samples from p(w) + if self.metric == "rbf": + self.w = np.sqrt(2 * self.gamma) * np.random.normal( + size=(self.D, self.dimension) + ) + elif self.metric == "laplace": + self.w = cauchy.rvs(scale=self.gamma, size=(self.D, self.dimension)) + # Generate D iid samples from Uniform(0,2*pi) + self.u = 2 * np.pi * np.random.rand(self.D) + + def obs_fcn(self, X: np.ndarray) -> np.ndarray: + # modification... + if len(X.shape) == 1: + x = np.atleast_2d(X.flatten()).T + else: + x = X.T + w = self.w.T + u = self.u[np.newaxis, :].T + s = np.sqrt(2 / self.D) + Z = s * np.cos(x.T @ w + u.T) + return Z.T + + def obs_grad(self, X: np.ndarray) -> np.ndarray: + if len(X.shape) == 1: + x = np.atleast_2d(X.flatten()).T + else: + x = X.T + x = np.atleast_2d(X.flatten()).T + w = self.w.T + u = self.u[np.newaxis, :].T + s = np.sqrt(2 / self.D) + # TODO: make this sparse? + Z = -s * np.diag(np.sin(u + w.T @ x).flatten()) @ w.T + return Z + + def compute_kernel(self, X: np.ndarray) -> np.ndarray: + Z = self.transform(X) + K = Z.dot(Z.T) + return K \ No newline at end of file diff --git a/notebooks/linear-model.ipynb b/notebooks/linear-model.ipynb index e3dfdfe..6d44c19 100644 --- a/notebooks/linear-model.ipynb +++ b/notebooks/linear-model.ipynb @@ -41,7 +41,7 @@ "metadata": {}, "outputs": [], "source": [ - "from autokoopman.core.observables import RFFObservable, PolynomialObservable, IdentityObservable\n", + "from autokoopman.observable import RFFObservable, PolynomialObservable, IdentityObservable\n", "\n", "# augment (combine) observables function\n", "# in this case, combine multiple lengthscales together\n", @@ -192,7 +192,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.7" + "version": "3.9.0" } }, "nbformat": 4, diff --git a/test/unit_test/test_koopman.py b/test/unit_test/test_koopman.py index ad4a24c..8165fef 100644 --- a/test/unit_test/test_koopman.py +++ b/test/unit_test/test_koopman.py @@ -12,7 +12,8 @@ def test_discrete_koopman(normalize): """tests the discrete time Koopman estimator""" from autokoopman.benchmark.pendulum import PendulumWithInput from autokoopman.core.trajectory import TrajectoriesData - from autokoopman.core.observables import IdentityObservable, RFFObservable + from autokoopman.observable.observables import IdentityObservable + from autokoopman.observable.rff import RFFObservable from autokoopman.estimator.koopman import KoopmanDiscEstimator import random @@ -62,7 +63,8 @@ def test_cont_koopman(normalize): """tests the continuous time Koopman estimator""" from autokoopman.benchmark.pendulum import PendulumWithInput from autokoopman.core.trajectory import TrajectoriesData - from autokoopman.core.observables import IdentityObservable, RFFObservable + from autokoopman.observable.observables import IdentityObservable + from autokoopman.observable.rff import RFFObservable from autokoopman.estimator.koopman import KoopmanContinuousEstimator import random