From 45bbfe0b3ddf35556f337fa032f6af29ba0e6046 Mon Sep 17 00:00:00 2001 From: shaowu Date: Wed, 7 Feb 2024 22:24:54 -0500 Subject: [PATCH] fix issues on the pytest version --- src/pykoopman/koopman.py | 2 +- src/pykoopman/regression/_base_ensemble.py | 18 +- test/regression/test_regressors.py | 344 ++++++++++----------- 3 files changed, 175 insertions(+), 189 deletions(-) diff --git a/src/pykoopman/koopman.py b/src/pykoopman/koopman.py index b797090..192c2d3 100644 --- a/src/pykoopman/koopman.py +++ b/src/pykoopman/koopman.py @@ -21,8 +21,8 @@ from .regression import DMDc from .regression import EDMDc from .regression import EnsembleBaseRegressor -from .regression import PyDMDRegressor from .regression import NNDMD +from .regression import PyDMDRegressor class Koopman(BaseEstimator): diff --git a/src/pykoopman/regression/_base_ensemble.py b/src/pykoopman/regression/_base_ensemble.py index df099fc..94f6afb 100644 --- a/src/pykoopman/regression/_base_ensemble.py +++ b/src/pykoopman/regression/_base_ensemble.py @@ -4,7 +4,6 @@ """ from __future__ import annotations -import numpy as np from sklearn.base import BaseEstimator from sklearn.base import clone from sklearn.base import TransformerMixin @@ -78,16 +77,10 @@ def fit(self, X, y, **fit_params): functions. """ - # if ( - # isinstance(X, np.ndarray) - # and isinstance(y, np.ndarray) - # and X.ndim == 2 - # and y.ndim == 2 - # ): - # case 2: x, y are 2D np.ndarray, must be 1-step, no validation - self._training_dim = y.ndim # transformers are designed to modify X which is 2d dimensional, we # need to modify y accordingly. + + self._training_dim = y.ndim if y.ndim == 1: y_2d = y.reshape(-1, 1) else: @@ -104,17 +97,12 @@ def fit(self, X, y, **fit_params): if self.regressor is None: from sklearn.linear_model import LinearRegression + self.regressor_ = LinearRegression() else: self.regressor_ = clone(self.regressor) self.regressor_.fit(X, y_trans, **fit_params) - # elif isinstance(X, list) and isinstance(y, list): - # # case 4: x, y are two lists of trajectories, we have validation data - # for - # - # else: - # raise ValueError("check `x` and `y` for `self.fit`") if hasattr(self.regressor_, "feature_names_in_"): self.feature_names_in_ = self.regressor_.feature_names_in_ diff --git a/test/regression/test_regressors.py b/test/regression/test_regressors.py index 99ea8d8..8e8ed25 100644 --- a/test/regression/test_regressors.py +++ b/test/regression/test_regressors.py @@ -1,173 +1,171 @@ -"""Tests for pykoopman.regression objects and methods.""" -from __future__ import annotations - -import numpy as np -import pytest -from pydmd import DMD -from pykoopman.regression import BaseRegressor -from pykoopman.regression import EDMD -from pykoopman.regression import KDMD -from pykoopman.regression import NNDMD -from pykoopman.regression import PyDMDRegressor -from sklearn.gaussian_process.kernels import RBF -import pykoopman as pk - - -class RegressorWithoutFit: - def __init__(self): - pass - - def predict(self, x): - return x - - -class RegressorWithoutPredict: - def __init__(self): - pass - - def fit(self, x): - return self - - -@pytest.mark.parametrize( - "regressor", [RegressorWithoutFit(), RegressorWithoutPredict()] -) -def test_bad_regressor_input(regressor): - """test if BaseRegressor is going to raise TypeError for wrong input""" - with pytest.raises(TypeError): - BaseRegressor(regressor) - - -@pytest.mark.parametrize( - "data_xy", - [ - # case 1,2 only work for pykoopman class - # case 1: single step single traj, no validation - (np.random.rand(200, 3), None), - # case 2: single step multiple traj, no validation - (np.random.rand(200, 3), np.random.rand(200, 3)), - ], -) -@pytest.mark.parametrize( - "regressor", - [ - EDMD(svd_rank=10), - PyDMDRegressor(DMD(svd_rank=10)), - KDMD(svd_rank=10, kernel=RBF(length_scale=1)), - ], -) -def test_fit_regressors(data_xy, regressor): - """test if using nndmd regressor alone will run the fit without error - - Note: - `pydmd.DMD` cannot be used to fit nonconsecutive data - """ - x, y = data_xy - regressor.fit(x, y) - - -@pytest.mark.parametrize( - "data_xy", - [ - # case 1,2 only work for pykoopman class - # case 1: single step single traj, no validation - ( - np.random.rand(200, 3), - None - ), - # case 2: single step multiple traj, no validation - ( - np.random.rand(200, 3), - np.random.rand(200, 3) # because "x" is not a list, so we think this - # is single step - ), - # case 3,4 works for regressor directly - # case 3: multiple traj, no validation - ( - [np.random.rand(200, 3), np.random.rand(100, 3)], # this is training - None # no validation - ), - # case 4: multiple traj, with validation - ( - [np.random.rand(100, 3), np.random.rand(100, 3)], # this is training - [np.random.rand(300, 3), np.random.rand(400, 3)], # this is validation - ), - ], -) -@pytest.mark.parametrize( - "regressor", - [ - NNDMD( - mode="Dissipative", - look_forward=2, - config_encoder=dict( - input_size=3, hidden_sizes=[32] * 2, output_size=4, activations="swish" - ), - config_decoder=dict( - input_size=4, hidden_sizes=[32] * 2, output_size=3, activations="linear" - ), - batch_size=512, - lbfgs=True, - normalize=False, - normalize_mode="max", - trainer_kwargs=dict(max_epochs=1), - ) - ], -) -def test_fit_nndmd_regressor(data_xy, regressor): - """test if using nndmd regressor alone will run the fit without error""" - x, y = data_xy - regressor.fit(x, y) - -@pytest.mark.parametrize( - "data_xy", - [ - # # case 1,2 only work for pykoopman class - # # case 1: single step single traj, no validation - # ( - # np.random.rand(200, 3), - # None - # ), - # # case 2: single step multiple traj, no validation - # ( - # np.random.rand(200, 3), - # np.random.rand(200, 3) # because "x" is not a list, so we think this - # # is single step - # ), - # # case 3,4 works for regressor directly - # # case 3: multiple traj, no validation - # ( - # [np.random.rand(200, 3), np.random.rand(100, 3)], # this is training - # None # no validation - # ), - # case 4: multiple traj, with validation - ( - [np.random.rand(100, 3), np.random.rand(100, 3)], # this is training - [np.random.rand(300, 3), np.random.rand(400, 3)], # this is validation - ), - ], -) -@pytest.mark.parametrize( - "regressor", - [ - NNDMD( - mode="Dissipative", - look_forward=2, - config_encoder=dict( - input_size=3, hidden_sizes=[32] * 2, output_size=4, activations="swish" - ), - config_decoder=dict( - input_size=4, hidden_sizes=[32] * 2, output_size=3, activations="linear" - ), - batch_size=512, - lbfgs=True, - normalize=False, - normalize_mode="max", - trainer_kwargs=dict(max_epochs=1), - ) - ], -) -def test_fit_dlkoopman(data_xy, regressor): - """test if using NNDMD regressor work inside pykoopman""" - model_d = pk.Koopman(regressor=regressor) - model_d.fit(data_xy[0],data_xy[1], dt=1) \ No newline at end of file +"""Tests for pykoopman.regression objects and methods.""" +from __future__ import annotations + +import numpy as np +import pykoopman as pk +import pytest +from pydmd import DMD +from pykoopman.regression import BaseRegressor +from pykoopman.regression import EDMD +from pykoopman.regression import KDMD +from pykoopman.regression import NNDMD +from pykoopman.regression import PyDMDRegressor +from sklearn.gaussian_process.kernels import RBF + + +class RegressorWithoutFit: + def __init__(self): + pass + + def predict(self, x): + return x + + +class RegressorWithoutPredict: + def __init__(self): + pass + + def fit(self, x): + return self + + +@pytest.mark.parametrize( + "regressor", [RegressorWithoutFit(), RegressorWithoutPredict()] +) +def test_bad_regressor_input(regressor): + """test if BaseRegressor is going to raise TypeError for wrong input""" + with pytest.raises(TypeError): + BaseRegressor(regressor) + + +@pytest.mark.parametrize( + "data_xy", + [ + # case 1,2 only work for pykoopman class + # case 1: single step single traj, no validation + (np.random.rand(200, 3), None), + # case 2: single step multiple traj, no validation + (np.random.rand(200, 3), np.random.rand(200, 3)), + ], +) +@pytest.mark.parametrize( + "regressor", + [ + EDMD(svd_rank=10), + PyDMDRegressor(DMD(svd_rank=10)), + KDMD(svd_rank=10, kernel=RBF(length_scale=1)), + ], +) +def test_fit_regressors(data_xy, regressor): + """test if using nndmd regressor alone will run the fit without error + + Note: + `pydmd.DMD` cannot be used to fit nonconsecutive data + """ + x, y = data_xy + regressor.fit(x, y) + + +@pytest.mark.parametrize( + "data_xy", + [ + # case 1,2 only work for pykoopman class + # case 1: single step single traj, no validation + (np.random.rand(200, 3), None), + # case 2: single step multiple traj, no validation + ( + np.random.rand(200, 3), + np.random.rand(200, 3) # because "x" is not a list, so we think this + # is single step + ), + # case 3,4 works for regressor directly + # case 3: multiple traj, no validation + ( + [np.random.rand(200, 3), np.random.rand(100, 3)], # this is training + None, # no validation + ), + # case 4: multiple traj, with validation + ( + [np.random.rand(100, 3), np.random.rand(100, 3)], # this is training + [np.random.rand(300, 3), np.random.rand(400, 3)], # this is validation + ), + ], +) +@pytest.mark.parametrize( + "regressor", + [ + NNDMD( + mode="Dissipative", + look_forward=2, + config_encoder=dict( + input_size=3, hidden_sizes=[32] * 2, output_size=4, activations="swish" + ), + config_decoder=dict( + input_size=4, hidden_sizes=[32] * 2, output_size=3, activations="linear" + ), + batch_size=512, + lbfgs=True, + normalize=False, + normalize_mode="max", + trainer_kwargs=dict(max_epochs=1), + ) + ], +) +def test_fit_nndmd_regressor(data_xy, regressor): + """test if using nndmd regressor alone will run the fit without error""" + x, y = data_xy + regressor.fit(x, y) + + +@pytest.mark.parametrize( + "data_xy", + [ + # # case 1,2 only work for pykoopman class + # # case 1: single step single traj, no validation + # ( + # np.random.rand(200, 3), + # None + # ), + # # case 2: single step multiple traj, no validation + # ( + # np.random.rand(200, 3), + # np.random.rand(200, 3) # because "x" is not a list, so we think this + # # is single step + # ), + # # case 3,4 works for regressor directly + # # case 3: multiple traj, no validation + # ( + # [np.random.rand(200, 3), np.random.rand(100, 3)], # this is training + # None # no validation + # ), + # case 4: multiple traj, with validation + ( + [np.random.rand(100, 3), np.random.rand(100, 3)], # this is training + [np.random.rand(300, 3), np.random.rand(400, 3)], # this is validation + ), + ], +) +@pytest.mark.parametrize( + "regressor", + [ + NNDMD( + mode="Dissipative", + look_forward=2, + config_encoder=dict( + input_size=3, hidden_sizes=[32] * 2, output_size=4, activations="swish" + ), + config_decoder=dict( + input_size=4, hidden_sizes=[32] * 2, output_size=3, activations="linear" + ), + batch_size=512, + lbfgs=True, + normalize=False, + normalize_mode="max", + trainer_kwargs=dict(max_epochs=1), + ) + ], +) +def test_fit_dlkoopman(data_xy, regressor): + """test if using NNDMD regressor work inside pykoopman""" + model_d = pk.Koopman(regressor=regressor) + model_d.fit(data_xy[0], data_xy[1], dt=1)