Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion docs/source/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ EZyRB requires:
- scipy
- matplotlib
- scikit-learn
- torch (for neural network-based methods)

Install via pip
---------------
Expand Down
23 changes: 18 additions & 5 deletions ezyrb/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
"""EZyRB package"""

__all__ = [
'Database', 'Snapshot', 'Reduction', 'POD', 'Approximation', 'RBF',
'Linear', 'GPR', 'ANN', 'KNeighborsRegressor',
'RadiusNeighborsRegressor', 'AE', 'ReducedOrderModel', 'PODAE',
'RegularGrid', 'MultiReducedOrderModel', 'SklearnApproximation',
'SklearnReduction'
"Database",
"Snapshot",
"Reduction",
"POD",
"Approximation",
"RBF",
"Linear",
"GPR",
"ANN",
"KNeighborsRegressor",
"RadiusNeighborsRegressor",
"AE",
"ReducedOrderModel",
"PODAE",
"RegularGrid",
"MultiReducedOrderModel",
"SklearnApproximation",
"SklearnReduction",
]

from .database import Database
Expand Down
11 changes: 8 additions & 3 deletions ezyrb/approximation/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
"""EZyRB package"""

__all__ = [
'Approximation', 'RBF', 'Linear', 'GPR',
'ANN', 'KNeighborsRegressor', 'RadiusNeighborsRegressor',
'SklearnApproximation'
"Approximation",
"RBF",
"Linear",
"GPR",
"ANN",
"KNeighborsRegressor",
"RadiusNeighborsRegressor",
"SklearnApproximation",
]

from .approximation import Approximation
Expand Down
9 changes: 9 additions & 0 deletions ezyrb/approximation/ann.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,16 @@ class ANN(Approximation):
>>> print(y_pred)
>>> print(len(ann.loss_trend))
>>> print(ann.loss_trend[-1])

.. note::
This module provides a wrapper around sklearn's MLPRegressor for
multidimensional function approximation using feed-forward neural
networks. It is not intended for deep learning tasks, but rather for
approximating functions based on given data points. For more advanced
deep learning applications, consider using dedicated libraries such as
:ref:`PINA`.
"""

def __init__(
self,
layers,
Expand Down
1 change: 1 addition & 0 deletions ezyrb/approximation/approximation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class Approximation(ABC):
All the classes that implement the input-output mapping should be inherited
from this class.
"""

@abstractmethod
def fit(self, points, values):
"""Abstract `fit`"""
Expand Down
35 changes: 23 additions & 12 deletions ezyrb/approximation/gpr.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Module wrapper exploiting `GPy` for Gaussian Process Regression
"""

import logging
import numpy as np
from scipy.optimize import minimize
Expand Down Expand Up @@ -40,19 +41,24 @@ class GPR(Approximation):
>>> print(np.allclose(y, y_pred))

"""

def __init__(self, kern=None, normalizer=True, optimization_restart=20):
"""
Initialize a Gaussian Process Regressor.

:param kern: Kernel object from sklearn. Default is None.
:param bool normalizer: Whether to normalize values. Default is True.
:param int optimization_restart: Number of restarts for optimization.
Default is 20.
"""

logger.debug("Initializing GPR with kernel=%s, normalizer=%s, "
"optimization_restart=%d",
kern, normalizer, optimization_restart)
logger.debug(
"Initializing GPR with kernel=%s, normalizer=%s, "
"optimization_restart=%d",
kern,
normalizer,
optimization_restart,
)
self.X_sample = None
self.Y_sample = None
self.kern = kern
Expand All @@ -67,8 +73,11 @@ def fit(self, points, values):
:param array_like points: the coordinates of the points.
:param array_like values: the values in the points.
"""
logger.debug("Fitting GPR with points shape: %s, values shape: %s",
np.array(points).shape, np.array(values).shape)
logger.debug(
"Fitting GPR with points shape: %s, values shape: %s",
np.array(points).shape,
np.array(values).shape,
)
self.X_sample = np.array(points)
self.Y_sample = np.array(values)
if self.X_sample.ndim == 1:
Expand All @@ -80,8 +89,10 @@ def fit(self, points, values):

logger.debug("Creating GaussianProcessRegressor")
self.model = GaussianProcessRegressor(
kernel=self.kern, n_restarts_optimizer=self.optimization_restart,
normalize_y=self.normalizer)
kernel=self.kern,
n_restarts_optimizer=self.optimization_restart,
normalize_y=self.normalizer,
)
self.model.fit(self.X_sample, self.Y_sample)
logger.info("GPR fitted successfully")

Expand Down Expand Up @@ -118,14 +129,14 @@ def optimal_mu(self, bounds, optimization_restart=10):
def min_obj(X):
return -1 * np.linalg.norm(self.predict(X.reshape(1, -1), True)[1])

initial_starts = np.random.uniform(bounds[:, 0],
bounds[:, 1],
size=(optimization_restart, dim))
initial_starts = np.random.uniform(
bounds[:, 0], bounds[:, 1], size=(optimization_restart, dim)
)

# Find the best optimum by starting from n_restart different random
# points.
for x0 in initial_starts:
res = minimize(min_obj, x0, bounds=bounds, method='L-BFGS-B')
res = minimize(min_obj, x0, bounds=bounds, method="L-BFGS-B")

if res.fun < min_val:
min_val = res.fun
Expand Down
12 changes: 7 additions & 5 deletions ezyrb/approximation/kneighbors_regressor.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ class KNeighborsRegressor(NeighborsRegressor):

:param kwargs: arguments passed to the internal instance of
KNeighborsRegressor.

:Example:

>>> import numpy as np
>>> from ezyrb import KNeighborsRegressor
>>> x = np.random.uniform(-1, 1, size=(20, 2))
Expand All @@ -26,12 +26,14 @@ class KNeighborsRegressor(NeighborsRegressor):
>>> new_x = np.array([[0.5, 0.5]])
>>> y_pred = knn.predict(new_x)
"""

def __init__(self, **kwargs):
"""
Initialize a K-Neighbors Regressor.

:param kwargs: Arguments passed to sklearn's KNeighborsRegressor.
"""
logger.debug("Initializing KNeighborsRegressor with kwargs: %s",
kwargs)
logger.debug(
"Initializing KNeighborsRegressor with kwargs: %s", kwargs
)
self.regressor = Regressor(**kwargs)
37 changes: 23 additions & 14 deletions ezyrb/approximation/linear.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ class Linear(Approximation):
of the convex hull of the input points. If not provided, then the
default is numpy.nan.
"""

def __init__(self, fill_value=np.nan):
"""
Initialize a Linear interpolator.

:param float fill_value: Value for points outside the convex hull.
Default is numpy.nan.
"""
Expand All @@ -38,33 +39,41 @@ def fit(self, points, values):
:param array_like points: the coordinates of the points.
:param array_like values: the values in the points.
"""
logger.debug("Fitting Linear with points shape: %s, "
"values shape: %s",
np.array(points).shape, np.array(values).shape)
logger.debug(
"Fitting Linear with points shape: %s, " "values shape: %s",
np.array(points).shape,
np.array(values).shape,
)
# the first dimension is the list of parameters, the second one is
# the dimensionality of each tuple of parameters (we look for
# parameters of dimensionality one)
as_np_array = np.array(points)
if not np.issubdtype(as_np_array.dtype, np.number):
logger.error("Invalid points format/dimension")
raise ValueError('Invalid format or dimension for the argument'
'`points`.')
raise ValueError(
"Invalid format or dimension for the argument" "`points`."
)

if as_np_array.shape[-1] == 1:
as_np_array = np.squeeze(as_np_array, axis=-1)
logger.debug("Squeezed points array")

if as_np_array.ndim == 1 or (as_np_array.ndim == 2
and as_np_array.shape[1] == 1):
if as_np_array.ndim == 1 or (
as_np_array.ndim == 2 and as_np_array.shape[1] == 1
):
logger.debug("Using 1D interpolation")
self.interpolator = interp1d(as_np_array, values, axis=0,
bounds_error=False,
fill_value=self.fill_value)
self.interpolator = interp1d(
as_np_array,
values,
axis=0,
bounds_error=False,
fill_value=self.fill_value,
)
else:
logger.debug("Using ND interpolation")
self.interpolator = LinearNDInterp(points,
values,
fill_value=self.fill_value)
self.interpolator = LinearNDInterp(
points, values, fill_value=self.fill_value
)
logger.info("Linear fitted successfully")

def predict(self, new_point):
Expand Down
7 changes: 4 additions & 3 deletions ezyrb/approximation/neighbors_regressor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
class NeighborsRegressor(Approximation):
"""
A generic superclass for wrappers of *NeighborsRegressor from sklearn.

This class provides a common interface for neighbor-based regression methods.

:param kwargs: Arguments passed to the internal instance of
*NeighborsRegressor.

:Example:

>>> import numpy as np
>>> from ezyrb import KNeighborsRegressor
>>> x = np.random.uniform(-1, 1, size=(20, 2))
Expand All @@ -23,6 +23,7 @@ class NeighborsRegressor(Approximation):
>>> knn.fit(x, y)
>>> y_pred = knn.predict(x[:5])
"""

def fit(self, points, values):
"""
Construct the interpolator given `points` and `values`.
Expand Down
7 changes: 4 additions & 3 deletions ezyrb/approximation/radius_neighbors_regressor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ class RadiusNeighborsRegressor(NeighborsRegressor):

:param kwargs: arguments passed to the internal instance of
RadiusNeighborsRegressor.

:Example:

>>> import numpy as np
>>> from ezyrb import RadiusNeighborsRegressor
>>> x = np.random.uniform(-1, 1, size=(20, 2))
Expand All @@ -23,10 +23,11 @@ class RadiusNeighborsRegressor(NeighborsRegressor):
>>> new_x = np.array([[0.0, 0.0]])
>>> y_pred = rnn.predict(new_x)
"""

def __init__(self, **kwargs):
"""
Initialize a Radius Neighbors Regressor.

:param kwargs: Arguments passed to sklearn's RadiusNeighborsRegressor.
"""
self.regressor = Regressor(**kwargs)
41 changes: 27 additions & 14 deletions ezyrb/approximation/rbf.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,24 @@ class RBF(Approximation):
>>> print(np.allclose(y, y_pred))

"""
def __init__(self,
kernel='thin_plate_spline',
smooth=0,
neighbors=None,
epsilon=None,
degree=None):
logger.debug("Initializing RBF with kernel=%s, smooth=%s, "
"neighbors=%s, epsilon=%s, degree=%s",
kernel, smooth, neighbors, epsilon, degree)

def __init__(
self,
kernel="thin_plate_spline",
smooth=0,
neighbors=None,
epsilon=None,
degree=None,
):
logger.debug(
"Initializing RBF with kernel=%s, smooth=%s, "
"neighbors=%s, epsilon=%s, degree=%s",
kernel,
smooth,
neighbors,
epsilon,
degree,
)
self.kernel = kernel
self.smooth = smooth
self.neighbors = neighbors
Expand All @@ -66,8 +75,11 @@ def fit(self, points, values):
:param array_like points: the coordinates of the points.
:param array_like values: the values in the points.
"""
logger.debug("Fitting RBF with points shape: %s, values shape: %s",
np.asarray(points).shape, np.asarray(values).shape)
logger.debug(
"Fitting RBF with points shape: %s, values shape: %s",
np.asarray(points).shape,
np.asarray(values).shape,
)
self.xi = np.asarray(points)

if self.epsilon is None:
Expand All @@ -78,8 +90,8 @@ def fit(self, points, values):
ximin = np.amin(self.xi, axis=0)
edges = ximax - ximin
edges = edges[np.nonzero(edges)]
self.epsilon = np.power(np.prod(edges)/N, 1.0/edges.size)
if self.kernel in ['thin_plate_spline', 'cubic', 'quintic']:
self.epsilon = np.power(np.prod(edges) / N, 1.0 / edges.size)
if self.kernel in ["thin_plate_spline", "cubic", "quintic"]:
self.epsilon = 1
logger.debug("Auto-computed epsilon: %f", self.epsilon)

Expand All @@ -91,7 +103,8 @@ def fit(self, points, values):
smoothing=self.smooth,
kernel=self.kernel,
epsilon=self.epsilon,
degree=self.degree)
degree=self.degree,
)
logger.info("RBF fitted successfully")

def predict(self, new_point):
Expand Down
Loading