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

Dev #46

Merged
merged 25 commits into from
Apr 24, 2024
Merged

Dev #46

Show file tree
Hide file tree
Changes from 19 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
3 changes: 2 additions & 1 deletion .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# F401: unused imports in __init__.py-s
# I251: allow absolute imports in upper files
# B028: !r is not supported for python<3.8
ignore = W503,E203,B028
# W604: backticks in str-s are ok
ignore = W503,E203,B028,W604
per-file-ignores =
__init__.py:F401
tests/*:I251
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v3
- uses: fregante/setup-git-user@v1
- run: git fetch origin gh-pages --depth=1
- uses: actions/setup-python@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install
Expand Down
15 changes: 9 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.9
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: 3.9

Expand Down Expand Up @@ -42,9 +42,9 @@ jobs:

steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: actions/setup-python@v5
- name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.10.0
run: python -m pip install cibuildwheel==2.17.0
- name: Install gcc for mac
if: matrix.os == 'macOS-11'
run: |
Expand Down Expand Up @@ -76,9 +76,10 @@ jobs:
python -m pip install --upgrade pip
python -m cibuildwheel --output-dir wheelhouse
env:
CIBW_ARCHS_MACOS: "x86_64 arm64"
CIBW_ENVIRONMENT_MACOS: >
PATH="/usr/local/opt/llvm/bin:$PATH" LDFLAGS="-L/usr/local/opt/llvm/lib" CPPFLAGS="-I/usr/local/opt/llvm/include"
CIBW_BUILD: cp36-* cp37-* cp38-* cp39-* cp310-* cp311-*
CIBW_BUILD: cp36-* cp37-* cp38-* cp39-* cp310-* cp311-* cp312-*
CIBW_BEFORE_BUILD_LINUX: 'if [ $(python -c "import sys; print(sys.version_info[1])") -ge 9 ]; then python -m pip install "numpy<2.0.0" --config-settings=setup-args="-Dallow-noblas=true"; fi'
- uses: actions/upload-artifact@v3
with:
Expand All @@ -90,9 +91,11 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.9
uses: actions/setup-python@v4
uses: actions/setup-python@v5
- name: Build
run: python setup.py sdist
run: |
pip install build
python -m build --sdist
- uses: actions/upload-artifact@v3
with:
path: dist/*.tar.gz
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/test_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ jobs:

steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: actions/setup-python@v5
with:
python-version: '3.9'
- name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.10.0
run: python -m pip install cibuildwheel==2.17.0
- name: Install gcc for mac
if: matrix.os == 'macOS-11'
run: |
Expand Down Expand Up @@ -52,6 +54,6 @@ jobs:
env:
CIBW_ENVIRONMENT_MACOS: >
PATH="/usr/local/opt/llvm/bin:$PATH" LDFLAGS="-L/usr/local/opt/llvm/lib" CPPFLAGS="-I/usr/local/opt/llvm/include"
CIBW_BUILD: cp39-* cp36-*
CIBW_BUILD: cp39-* cp36-* cp312-*
CIBW_SKIP: "*musllinux* *manylinux_x86_64"
CIBW_BEFORE_BUILD_LINUX: 'if [ $(python -c "import sys; print(sys.version_info[1])") -ge 9 ]; then python -m pip install "numpy<2.0.0" --config-settings=setup-args="-Dallow-noblas=true"; fi'
7 changes: 4 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
python-version: [ '3.6', '3.7', '3.8', '3.9', '3.10', '3.11']
python-version: [ '3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12']

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

Expand All @@ -28,7 +28,8 @@ jobs:
if [ "$GITHUB_BASE_REF" = "master" ] && [ "$MATCH" != "" ]; then exit 1; fi
- name: Build the package
run: |
python setup.py sdist
pip install build
python -m build --sdist

- name: Install
run: |
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ y = zoom(x, 2, axis=[0, 1])
# without the need to compute the scale factor
z = zoom_to_shape(x, (4, 120, 67))
```
Works faster only for `ndim<=4, dtype=float32 or float64 (and bool-int16-32-64 if order == 0), output=None, order=0 or 1, mode='constant', grid_mode=False`
Works faster only for `ndim<=4, dtype=float32 or float64 (and bool-int16-32-64-uint8-16-32 if order == 0), output=None, order=0 or 1, mode='constant', grid_mode=False`
### Fast 1d linear interpolation

```python
Expand Down
2 changes: 1 addition & 1 deletion imops/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.8.6'
__version__ = '0.8.7'
7 changes: 7 additions & 0 deletions imops/crop.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ def crop_to_shape(x: np.ndarray, shape: AxesLike, axis: AxesLike = None, ratio:
>>> cropped = crop_to_shape(x, [3, 4, 5]) # fail due to bigger resulting shape
"""
x = np.asarray(x)
shape = np.asarray(shape)
if not np.issubdtype(shape.dtype, np.integer):
raise ValueError(f'`shape` must be of integer dtype, got {shape.dtype}')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mb move this to a function? we're using this logic in several places anyway

axis, shape, ratio = broadcast_axis(axis, x.ndim, shape, ratio)

old_shape, new_shape = np.array(x.shape), np.array(fill_by_indices(x.shape, shape, axis))
Expand Down Expand Up @@ -89,6 +92,10 @@ def crop_to_box(
>>> cropped = crop_to_box(x, np.array([[0], [5]]), axis=0, padding_values=0) # pad with 0-s to shape [5, 3, 4]
"""
x = np.asarray(x)
box = np.asarray(box)
if not np.issubdtype(box.dtype, np.integer):
raise ValueError(f'`box` must be of integer dtype, got {box.dtype}')

start, stop = box
axis, start, stop = broadcast_axis(axis, x.ndim, start, stop)

Expand Down
26 changes: 23 additions & 3 deletions imops/interp1d.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@
njit_kwargs = {kwarg: getattr(backend, kwarg) for kwarg in backend.__dataclass_fields__.keys()}
self.src_interp1d = njit(**njit_kwargs)(numba_interp1d)

def __call__(self, x_new: np.ndarray) -> np.ndarray:
def __call__(self, x_new: np.ndarray, use_torch: bool = False) -> np.ndarray:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use_torch is too hacky. m.b. this should be specified through the backend?

if use_torch:
import torch

Check warning on line 142 in imops/interp1d.py

View check run for this annotation

Codecov / codecov/patch

imops/interp1d.py#L142

Added line #L142 was not covered by tests
"""
Evaluate the interpolant

Expand Down Expand Up @@ -180,14 +182,32 @@
if self.backend.name == 'Numba':
set_num_threads(old_num_threads)

out = out.astype(max(self.y.dtype, self.x.dtype, x_new.dtype, key=lambda x: x.type(0).itemsize), copy=False)
if use_torch:
out = (
torch.from_numpy(out)
.to(
max(
torch.from_numpy(self.y).dtype,
torch.from_numpy(self.x).dtype,
torch.from_numpy(x_new).dtype,
key=lambda x: x.itemsize,
)
)
.numpy()
)
else:
out = out.astype(max(self.y.dtype, self.x.dtype, x_new.dtype, key=lambda x: x.type(0).itemsize), copy=False)

if self.n_dummy:
out = out[(0,) * self.n_dummy]
if self.axis not in (-1, out.ndim - 1):
out = np.swapaxes(out, -1, self.axis)
# FIXME: fix behaviour with np.inf-s
if np.isnan(out).any():
if use_torch:
have_nan = torch.isnan(torch.from_numpy(out)).any()

Check warning on line 207 in imops/interp1d.py

View check run for this annotation

Codecov / codecov/patch

imops/interp1d.py#L207

Added line #L207 was not covered by tests
else:
have_nan = np.isnan(out).any()
if have_nan:
if not np.isinf(out).any():
raise RuntimeError("Can't decide how to handle nans in the output.")

Expand Down
4 changes: 2 additions & 2 deletions imops/morphology.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,13 @@ def wrapped(
raise ValueError('Input image and footprint number of dimensions must be the same.')

if not image.any():
warn(f'{op_name} is applied to the fully False mask (mask.any() == False).', stacklevel=3)
warn(f'{op_name} is applied to the fully False mask (mask.any() == False).', stacklevel=3) # noqa
output.fill(False)

return output

if image.all():
warn(f'{op_name} is applied to the fully True mask (mask.all() == True).', stacklevel=3)
warn(f'{op_name} is applied to the fully True mask (mask.all() == True).', stacklevel=3) # noqa
output.fill(True)

return output
Expand Down
2 changes: 2 additions & 0 deletions imops/src/_zoom.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ from libc.math cimport floor, sqrt
ctypedef cython.floating FLOAT
ctypedef fused NUM:
np.uint8_t
np.uint16_t
np.uint32_t
short
int
long long
Expand Down
13 changes: 7 additions & 6 deletions imops/zoom.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def zoom(
"""
Rescale `x` according to `scale_factor` along the `axis`.

Uses a fast parallelizable implementation for fp32 / fp64 (and bool-int16-32-64 if order == 0) inputs,
Uses a fast parallelizable implementation for fp32-fp64 and bool-int16-32-64-uint8-16-32 if order == 0 inputs,
ndim <= 4 and order = 0 or 1.

Parameters
Expand Down Expand Up @@ -136,7 +136,7 @@ def zoom_to_shape(
"""
Rescale `x` to match `shape` along the `axis`.

Uses a fast parallelizable implementation for fp32 / fp64 (and bool-int16-32-64 if order == 0) inputs,
Uses a fast parallelizable implementation for fp32-fp64 and bool-int16-32-64-uint8-16-32 if order == 0 inputs,
ndim <= 4 and order = 0 or 1.

Parameters
Expand Down Expand Up @@ -198,7 +198,7 @@ def _zoom(
backend: BackendLike = None,
) -> np.ndarray:
"""
Faster parallelizable version of `scipy.ndimage.zoom` for fp32 / fp64 (and bool-int16-32-64 if order == 0) inputs.
Faster parallelizable version of `scipy.ndimage.zoom` for fp32-fp64 and bool-int16-32-64-uint8-16-32 if order == 0

Works faster only for ndim <= 4. Shares interface with `scipy.ndimage.zoom`
except for
Expand Down Expand Up @@ -228,16 +228,17 @@ def _zoom(
or (
dtype not in (np.float32, np.float64)
if order == 1
else dtype not in (bool, np.float32, np.float64, np.int16, np.int32, np.int64)
else dtype
not in (bool, np.float32, np.float64, np.int16, np.int32, np.int64, np.uint8, np.uint16, np.uint32)
)
or ndim > 4
or output is not None
or mode != 'constant'
or grid_mode
):
warn(
'Fast zoom is only supported for ndim<=4, dtype=fp32 or fp64 (and bool-int16-32-64 if order == 0), '
"output=None, order=0 or 1, mode='constant', grid_mode=False. Falling back to scipy's implementation.",
'Fast zoom is only supported for ndim<=4, dtype=fp32-fp64 and bool-int16-32-64-uint8-16-32 if order == 0, '
"output=None, order=0 or 1 , mode='constant', grid_mode=False. Falling back to scipy's implementation.",
stacklevel=3,
)
return scipy_zoom(
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ classifiers = [
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
]

[options]
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
]

with open(root / 'requirements.txt', encoding='utf-8') as file:
Expand Down
16 changes: 15 additions & 1 deletion tests/test_crop.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,21 @@ def test_raises():
@seeded_by(SEED)
def test_crop_to_shape():
x = np.random.rand(3, 10, 10)
shape = 3, 4, 8
shape = (3, 4, 8)
assert crop_to_shape(x, shape).shape == shape
with pytest.raises(ValueError):
crop_to_shape(x, (3, 15, 10))


def test_crop_to_float_shape():
x = np.random.rand(3, 10, 10)
float_shape = (1.337, 3.1415, 2.7182)
with pytest.raises(ValueError):
crop_to_shape(x, float_shape)


def test_crop_to_float_box():
x = np.random.rand(3, 10, 10)
float_box = [[0, 1], [4, 4.5], [3.1, 9]]
with pytest.raises(ValueError):
crop_to_box(x, float_box)
3 changes: 3 additions & 0 deletions tests/test_pad.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ def test_restore_crop_invalid_box():
with pytest.raises(ValueError):
restore_crop(x, np.array([[0, 0, 0], [1, 1, 1]]), [4, 4, 4])

with pytest.raises(ValueError):
restore_crop(x, np.array([[0.5, 0.5, 0.5], [1.5, 1.5, 1.5]]), [4.5, 4.5, 4.5])


def test_pad_to_divisible():
x = np.zeros((4, 8, 12))
Expand Down
2 changes: 1 addition & 1 deletion tests/test_zoom.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def order(request):
return request.param


@pytest.fixture(params=[np.float32, np.float64, bool, np.int16, np.int32, np.int64])
@pytest.fixture(params=[np.float32, np.float64, bool, np.int16, np.int32, np.int64, np.uint8, np.uint16, np.uint32])
def dtype(request):
return request.param

Expand Down
Loading