Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update packaging #83

Merged
merged 2 commits into from
Jun 30, 2024
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
13 changes: 6 additions & 7 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ jobs:
max-parallel: 8
matrix:
platform: [ "ubuntu-latest", "macos-latest", "windows-latest" ]
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ]
poetry-version: [ "1.7.1" ]
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
poetry-version: [ "1.8.3" ]

steps:
- name: Checkout project
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Poetry ${{ matrix.poetry-version }}
uses: abatilo/actions-poetry@v2
uses: abatilo/actions-poetry@v3
with:
poetry-version: ${{ matrix.poetry-version }}

Expand All @@ -36,7 +36,7 @@ jobs:
poetry config virtualenvs.in-project true --local

- name: Define a cache for the virtual environment based on the dependencies lock file
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ./.venv
key: venv-${{ hashFiles('poetry.lock') }}
Expand All @@ -47,7 +47,6 @@ jobs:
- name: Run static analysis and linters
run: |
poetry run ruff check .
poetry run isort -c .

- name: Run tests
run: poetry run pytest -v --color=yes --cov=csaps --cov-report=term --cov-report=lcov:coverage.info
Expand Down
12 changes: 12 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks

repos:
- repo: local
hooks:
- id: ruff
name: ruff
entry: poetry run ruff check
language: system
types: [python]
require_serial: true
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Use pip for installing:
pip install -U csaps
```

The module depends only on NumPy and SciPy. Python 3.6 or above is supported.
The module depends only on NumPy and SciPy. Python 3.9 or above is supported.

## Simple Examples

Expand Down
2 changes: 0 additions & 2 deletions csaps/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@
# Shortcut
'csaps',
'AutoSmoothingResult',

# Classes
'ISplinePPForm',
'ISmoothingSpline',
'SplinePPForm',
'NdGridSplinePPForm',
'CubicSmoothingSpline',
'NdGridCubicSmoothingSpline',

# Type-hints
'UnivariateDataType',
'MultivariateDataType',
Expand Down
15 changes: 5 additions & 10 deletions csaps/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@


class ISplinePPForm(abc.ABC, Generic[TData, TProps]):
"""The interface class for spline representation in PP-form
"""
"""The interface class for spline representation in PP-form"""

__module__ = 'csaps'

Expand Down Expand Up @@ -84,24 +83,20 @@ def shape(self) -> Tuple[int, ...]:


class ISmoothingSpline(abc.ABC, Generic[TSpline, TSmooth, TXi, TNu, TExtrapolate]):
"""The interface class for smooting splines
"""
"""The interface class for smooting splines"""

__module__ = 'csaps'

@property
@abc.abstractmethod
def smooth(self) -> TSmooth:
"""Returns smoothing factor(s)
"""
"""Returns smoothing factor(s)"""

@property
@abc.abstractmethod
def spline(self) -> TSpline:
"""Returns spline representation in PP-form
"""
"""Returns spline representation in PP-form"""

@abc.abstractmethod
def __call__(self, xi: TXi, nu: Optional[TNu] = None, extrapolate: Optional[TExtrapolate] = None) -> np.ndarray:
"""Evaluates spline on the data sites
"""
"""Evaluates spline on the data sites"""
2 changes: 1 addition & 1 deletion csaps/_reshape.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def umv_coeffs_to_flatten(arr: np.ndarray):
strides = arr.strides[:-3:-1]
arr_view = as_strided(arr, shape=shape, strides=strides)
else: # pragma: no cover
raise ValueError(f"The array ndim must be 2 or 3, but given array has ndim={arr.ndim}.")
raise ValueError(f'The array ndim must be 2 or 3, but given array has ndim={arr.ndim}.')

return arr_view

Expand Down
12 changes: 5 additions & 7 deletions csaps/_sspndg.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ def coeffs(self) -> np.ndarray:

@property
def order(self) -> Tuple[int, ...]:
return self.c.shape[:self.c.ndim // 2]
return self.c.shape[: self.c.ndim // 2]

@property
def pieces(self) -> Tuple[int, ...]:
return self.c.shape[self.c.ndim // 2:]
return self.c.shape[self.c.ndim // 2 :]

@property
def ndim(self) -> int:
Expand Down Expand Up @@ -112,7 +112,7 @@ def __call__(
raise ValueError(f"'x' sequence must have length {self.ndim} according to 'breaks'")

if nu is None:
nu = (0, ) * len(x)
nu = (0,) * len(x)

if extrapolate is None:
extrapolate = True
Expand Down Expand Up @@ -210,7 +210,6 @@ def __init__(
smooth: Optional[Union[float, Sequence[Optional[float]]]] = None,
normalizedsmooth: bool = False,
) -> None:

x, y, w, s = self._prepare_data(xdata, ydata, weights, smooth)
coeffs, smooth = self._make_spline(x, y, w, s, normalizedsmooth)

Expand Down Expand Up @@ -306,8 +305,7 @@ def _prepare_data(cls, xdata, ydata, weights, smooth):

if len(smooth) != data_ndim:
raise ValueError(
'Number of smoothing parameter values must '
f'be equal number of dimensions ({data_ndim})'
'Number of smoothing parameter values must ' f'be equal number of dimensions ({data_ndim})'
)

return xdata, ydata, weights, smooth
Expand All @@ -324,7 +322,7 @@ def _make_spline(xdata, ydata, weights, smooth, normalizedsmooth):
smooth=smooth[0],
normalizedsmooth=normalizedsmooth,
)
return s.spline.coeffs, (s.smooth, )
return s.spline.coeffs, (s.smooth,)

shape = ydata.shape
coeffs = ydata
Expand Down
24 changes: 11 additions & 13 deletions csaps/_sspumv.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ def ndim(self) -> int:

@property
def shape(self) -> Tuple[int, ...]:
"""Returns the source data shape
"""
"""Returns the source data shape"""
shape: List[int] = list(self.c.shape[2:])
shape.insert(self.axis, self.c.shape[1] + 1)

Expand Down Expand Up @@ -124,7 +123,6 @@ def __init__(
axis: int = -1,
normalizedsmooth: bool = False,
):

x, y, w, shape, axis = self._prepare_data(xdata, ydata, weights, axis)
coeffs, smooth = self._make_spline(x, y, w, smooth, shape, normalizedsmooth)
spline = SplinePPForm.construct_fast(coeffs, x, axis=axis)
Expand Down Expand Up @@ -236,7 +234,7 @@ def _compute_smooth(a, b):
def trace(m: sp.dia_matrix):
return m.diagonal().sum()

return 1. / (1. + trace(a) / (6. * trace(b)))
return 1.0 / (1.0 + trace(a) / (6.0 * trace(b)))

@staticmethod
def _normalize_smooth(x: np.ndarray, w: np.ndarray, smooth: Optional[float]):
Expand All @@ -246,8 +244,8 @@ def _normalize_smooth(x: np.ndarray, w: np.ndarray, smooth: Optional[float]):

span = np.ptp(x)

eff_x = 1 + (span**2) / np.sum(np.diff(x)**2)
eff_w = np.sum(w)**2 / np.sum(w**2)
eff_x = 1 + (span**2) / np.sum(np.diff(x) ** 2)
eff_w = np.sum(w) ** 2 / np.sum(w**2)
k = 80 * (span**3) * (x.size**-2) * (eff_x**-0.5) * (eff_w**-0.5)

s = 0.5 if smooth is None else smooth
Expand Down Expand Up @@ -281,11 +279,11 @@ def _make_spline(x, y, w, smooth, shape, normalizedsmooth):
diags_r = np.vstack((dx[1:], 2 * (dx[1:] + dx[:-1]), dx[:-1]))
r = sp.spdiags(diags_r, [-1, 0, 1], pcount - 2, pcount - 2)

dx_recip = 1. / dx
dx_recip = 1.0 / dx
diags_qtw = np.vstack((dx_recip[:-1], -(dx_recip[1:] + dx_recip[:-1]), dx_recip[1:]))
diags_sqrw_recip = 1. / np.sqrt(w)
diags_sqrw_recip = 1.0 / np.sqrt(w)

qtw = (sp.diags(diags_qtw, [0, 1, 2], (pcount - 2, pcount)) @ sp.diags(diags_sqrw_recip, 0, (pcount, pcount)))
qtw = sp.diags(diags_qtw, [0, 1, 2], (pcount - 2, pcount)) @ sp.diags(diags_sqrw_recip, 0, (pcount, pcount))
qtw = qtw @ qtw.T

p = smooth
Expand All @@ -295,7 +293,7 @@ def _make_spline(x, y, w, smooth, shape, normalizedsmooth):
elif smooth is None:
p = CubicSmoothingSpline._compute_smooth(r, qtw)

pp = (6. * (1. - p))
pp = 6.0 * (1.0 - p)

# Solve linear system for the 2nd derivatives
a = pp * qtw + p * r
Expand All @@ -314,15 +312,15 @@ def _make_spline(x, y, w, smooth, shape, normalizedsmooth):
d1 = np.diff(vpad(u), axis=0) / dx
d2 = np.diff(vpad(d1), axis=0)

diags_w_recip = 1. / w
diags_w_recip = 1.0 / w
w = sp.diags(diags_w_recip, 0, (pcount, pcount))

yi = y.T - (pp * w) @ d2
pu = vpad(p * u)

c1 = np.diff(pu, axis=0) / dx
c2 = 3. * pu[:-1, :]
c3 = np.diff(yi, axis=0) / dx - dx * (2. * pu[:-1, :] + pu[1:, :])
c2 = 3.0 * pu[:-1, :]
c3 = np.diff(yi, axis=0) / dx - dx * (2.0 * pu[:-1, :] + pu[1:, :])
c4 = yi[:-1, :]

c_shape = (4, pcount - 1) + shape[1:]
Expand Down
5 changes: 3 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

def _get_version():
from csaps import __version__

return __version__


Expand Down Expand Up @@ -54,10 +55,10 @@ def _get_version():
'figure.autolayout': 'True',
'figure.figsize': '5, 3.5',
'savefig.bbox': 'tight',
'savefig.facecolor': "None",
'savefig.facecolor': 'None',
}

plot_formats = [("png", 90)]
plot_formats = [('png', 90)]
plot_include_source = True
plot_html_show_source_link = False
plot_html_show_formats = False
Expand Down
Loading