Skip to content

Commit 0ab389f

Browse files
authored
Merge pull request #1310 from kohr-h/npy19
BLD: add travis test with Numpy 1.10 and drop 1.9 support
2 parents b0beeff + d87718c commit 0ab389f

File tree

12 files changed

+72
-107
lines changed

12 files changed

+72
-107
lines changed

.gitignore

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,38 @@
1+
## Custom stuff
2+
3+
# vim viles
4+
*.swp
5+
*.swo
6+
*~
7+
8+
# Spyder project files
9+
.spyproject/
10+
.spyderproject
11+
.spyderworkspace
12+
.spyproject/
13+
14+
# PyCharm project files
15+
.idea
16+
17+
# VS Code files
18+
.vscode/
19+
20+
# IPython / Jupyter notebook files
21+
*.ipynb
22+
.ipynb_checkpoints
23+
24+
# caches
25+
.pytest_cache/
26+
27+
# Sphinx documentation
28+
doc/_build/
29+
doc/source/generated
30+
doc/source/odl_interface
31+
doc/source/odl*.rst
32+
33+
34+
## Python
35+
136
# Byte-compiled / optimized / DLL files
237
__pycache__/
338
*.py[cod]
@@ -51,46 +86,18 @@ coverage.xml
5186
# Django stuff:
5287
*.log
5388

54-
# Sphinx documentation
55-
doc/_build/
56-
doc/source/generated
57-
doc/source/odl_interface
58-
doc/source/odl*.rst
59-
6089
# PyBuilder
6190
target/
6291

6392
# Backups from futurize/pasteurize
6493
*.py.bak
6594

66-
# Visual studio
95+
96+
## Visual studio
6797
*.sdf
6898
*.sln
6999
*.suo
70100
*.pyproj
71101
*.pyproj.user
72102
*.pyperf
73103
*.psess
74-
75-
# vim viles
76-
*.swp
77-
*.swo
78-
*~
79-
80-
# Spyder project files
81-
.spyproject/
82-
.spyderproject
83-
.spyderworkspace
84-
.spyproject/
85-
86-
# PyCharm project files
87-
.idea
88-
89-
# VS Code files
90-
.vscode/
91-
92-
# IPython / Jupyter notebook files
93-
*.ipynb
94-
.ipynb_checkpoints
95-
96-
# Documentation build files

.travis.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ matrix:
55
- python: 2.7
66
env: NUMPY_VERSION=1.13
77

8+
- python: 3.6
9+
env: NUMPY_VERSION=1.10.1
10+
811
- python: 3.6
912
env: NUMPY_VERSION=1.12
1013

@@ -46,9 +49,10 @@ install:
4649
# make it run faster and avoid downloading big stuff like mkl
4750
- conda create -n testenv python=$TRAVIS_PYTHON_VERSION nomkl pywavelets
4851
- source activate testenv
49-
# We avoid annoying issues with building pyfftw wheels by using a conda-forge version
50-
- pip install "numpy==$NUMPY_VERSION" scipy future scikit-image pytest pytest-cov # faster than conda
51-
- conda install -c conda-forge pyfftw # compilation sometimes breaks on pip, using conda therefore
52+
# Install packages with pip if possible, it's way faster
53+
- pip install "numpy==$NUMPY_VERSION" scipy future scikit-image pytest pytest-cov;
54+
# Building pyfftw wheels sometimes fails, using a conda-forge version instead
55+
- conda install -c conda-forge pyfftw
5256

5357
# Doc dependencies
5458
- if [[ "$BUILD_DOCS" == "true" ]]; then

conda/meta.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ requirements:
1919
- setuptools
2020
- nomkl # [not win]
2121
- future >=0.14
22-
- numpy >=1.9
22+
- numpy >=1.10
2323
- scipy >=0.14
2424
run:
2525
- python
2626
- future >=0.14
2727
- nomkl # [not win]
28-
- numpy >=1.9
28+
- numpy >=1.10
2929
- scipy >=0.14
3030
- matplotlib
3131
- pytest >=3.0.3

odl/space/fspace.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
is_real_dtype, is_complex_floating_dtype, dtype_repr, dtype_str,
2222
complex_dtype, real_dtype, signature_string,
2323
is_valid_input_array, is_valid_input_meshgrid,
24-
out_shape_from_array, out_shape_from_meshgrid, vectorize, broadcast_to,
25-
writable_array)
24+
out_shape_from_array, out_shape_from_meshgrid, vectorize, writable_array)
2625
from odl.util.utility import preload_first_arg, getargspec
2726

2827

@@ -93,7 +92,7 @@ def _default_in_place(func, x, out, **kwargs):
9392
else:
9493
raise RuntimeError('bad input')
9594

96-
bcast_results = [broadcast_to(res, scalar_out_shape)
95+
bcast_results = [np.broadcast_to(res, scalar_out_shape)
9796
for res in flat_results]
9897
# New array that is flat in the `out_shape` axes, reshape it
9998
# to the final `out_shape + scalar_shape`, using the same
@@ -569,7 +568,7 @@ def wrapper(x, out=None, **kwargs):
569568
reshaped = np.reshape(res, scalar_out_shape)
570569
except ValueError:
571570
bcast_results.append(
572-
broadcast_to(res, scalar_out_shape))
571+
np.broadcast_to(res, scalar_out_shape))
573572
else:
574573
bcast_results.append(reshaped)
575574

@@ -1331,7 +1330,7 @@ def __call__(self, x, out=None, **kwargs):
13311330
# Broadcast the returned element, but not in the
13321331
# scalar case. The resulting array may be read-only,
13331332
# in which case we copy.
1334-
out = broadcast_to(out, out_shape)
1333+
out = np.broadcast_to(out, out_shape)
13351334
if not out.flags.writeable:
13361335
out = out.copy()
13371336

@@ -1353,7 +1352,8 @@ def __call__(self, x, out=None, **kwargs):
13531352
shp = getattr(res, 'shape', ())
13541353
if shp and shp[0] == 1:
13551354
res = res.reshape(res.shape[1:])
1356-
bcast_res.append(broadcast_to(res, scalar_out_shape))
1355+
bcast_res.append(
1356+
np.broadcast_to(res, scalar_out_shape))
13571357

13581358
out_arr = np.array(bcast_res,
13591359
dtype=self.space.scalar_out_dtype)

odl/test/space/tensors_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,11 +1358,11 @@ def test_ufuncs(tspace, ufunc):
13581358
data_elem = elements[0]
13591359

13601360
out_elems = elements[nin:]
1361-
out_arr_kwargs = {'out': out_arrays[:nout]}
1362-
13631361
if nout == 1:
1362+
out_arr_kwargs = {'out': out_arrays[0]}
13641363
out_elem_kwargs = {'out': out_elems[0]}
13651364
elif nout > 1:
1365+
out_arr_kwargs = {'out': out_arrays[:nout]}
13661366
out_elem_kwargs = {'out': out_elems[:nout]}
13671367

13681368
# Get function to call, using both interfaces:

odl/tomo/analytic/filtered_back_projection.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
from odl.discr import ResizingOperator
1313
from odl.trafos import FourierTransform, PYFFTW_AVAILABLE
14-
from odl.util.npy_compat import broadcast_to
1514

1615

1716
__all__ = ('fbp_op', 'fbp_filter_op', 'tam_danielson_window',
@@ -293,7 +292,7 @@ def b(alpha):
293292

294293
scale = 0.5 * alen / np.pi
295294
return ray_trafo.range.element(
296-
broadcast_to(S_sum * scale, ray_trafo.range.shape))
295+
np.broadcast_to(S_sum * scale, ray_trafo.range.shape))
297296

298297

299298
def fbp_filter_op(ray_trafo, padding=True, filter_type='Ram-Lak',

odl/tomo/backends/astra_setup.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
Geometry, DivergentBeamGeometry, ParallelBeamGeometry,
4040
Flat1dDetector, Flat2dDetector)
4141
from odl.tomo.util.utility import euler_matrix
42+
from odl.util.npy_compat import moveaxis
4243

4344
# Make sure that ASTRA >= 1.7 is used
4445
if ASTRA_AVAILABLE:
@@ -275,7 +276,7 @@ def astra_conebeam_3d_geom_to_vec(geometry):
275276

276277
# Vectors from detector pixel (0, 0) to (1, 0) and (0, 0) to (0, 1)
277278
# `det_axes` gives shape (N, 2, 3), swap to get (2, N, 3)
278-
det_axes = np.moveaxis(geometry.det_axes(angles), -2, 0)
279+
det_axes = moveaxis(geometry.det_axes(angles), -2, 0)
279280
px_sizes = geometry.det_partition.cell_sides
280281
# Swap detector axes to have better memory layout in projection data.
281282
# ASTRA produces `(v, theta, u)` layout, and to map to ODL layout
@@ -403,7 +404,7 @@ def astra_parallel_3d_geom_to_vec(geometry):
403404

404405
# Vectors from detector pixel (0, 0) to (1, 0) and (0, 0) to (0, 1)
405406
# `det_axes` gives shape (N, 2, 3), swap to get (2, N, 3)
406-
det_axes = np.moveaxis(geometry.det_axes(angles), -2, 0)
407+
det_axes = moveaxis(geometry.det_axes(angles), -2, 0)
407408
px_sizes = geometry.det_partition.cell_sides
408409
# Swap detector axes to have better memory layout in projection data.
409410
# ASTRA produces `(v, theta, u)` layout, and to map to ODL layout

odl/tomo/geometry/detector.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from odl.discr import RectPartition
1616
from odl.tomo.util import perpendicular_vector, is_inside_bounds
1717
from odl.util import indent, signature_string, array_str
18+
from odl.util.npy_compat import moveaxis
1819

1920

2021
__all__ = ('Detector',
@@ -187,7 +188,7 @@ def surface_normal(self, param):
187188
deriv = self.surface_deriv(param)
188189
if deriv.ndim > 2:
189190
# Vectorized, need to reshape (N, 2, 3) to (2, N, 3)
190-
deriv = np.moveaxis(deriv, -2, 0)
191+
deriv = moveaxis(deriv, -2, 0)
191192
normal = np.cross(*deriv, axis=-1)
192193
normal /= np.linalg.norm(normal, axis=-1, keepdims=True)
193194
return normal
@@ -243,7 +244,7 @@ def surface_measure(self, param):
243244
deriv = self.surface_deriv(param)
244245
if deriv.ndim > 2:
245246
# Vectorized, need to reshape (N, 2, 3) to (2, N, 3)
246-
deriv = np.moveaxis(deriv, -2, 0)
247+
deriv = moveaxis(deriv, -2, 0)
247248
cross = np.cross(*deriv, axis=-1)
248249
measure = np.linalg.norm(cross, axis=-1)
249250
if scalar_out:
@@ -401,10 +402,9 @@ def surface_deriv(self, param):
401402
return self.axis
402403
else:
403404
# Produce array of shape `param.shape + (ndim,)` by broadcasting
404-
axis_slc = (None,) * param.ndim + (slice(None),)
405-
# TODO: use broadcast_to from Numpy when v1.10 is required
406-
zeros = np.zeros(param.shape + (1,))
407-
return self.axis[axis_slc] + zeros
405+
bcast_slc = (None,) * param.ndim + (slice(None),)
406+
return np.broadcast_to(
407+
self.axis[bcast_slc], param.shape + self.axis.shape)
408408

409409
def __repr__(self):
410410
"""Return ``repr(self)``."""
@@ -611,13 +611,8 @@ def surface_deriv(self, param):
611611
if squeeze_out:
612612
return self.axes
613613
else:
614-
# Produce array of shape `broadcast(*param).shape + (2, 3)`
615-
# by explicit broadcasting.
616-
# TODO: use broadcast_to from Numpy when v1.10 is required
617-
axes_slc = ((None,) * len(np.broadcast(*param).shape) +
618-
(slice(None), slice(None)))
619-
zeros = np.zeros(np.broadcast(*param).shape + (1, 1))
620-
return self.axes[axes_slc] + zeros
614+
return np.broadcast_to(
615+
self.axes, np.broadcast(*param).shape + self.axes.shape)
621616

622617
def __repr__(self):
623618
"""Return ``repr(self)``."""

odl/util/normalize.py

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -106,29 +106,8 @@ def normalized_scalar_param_list(param, length, param_conv=None,
106106
raise ValueError('`length` must be nonnegative, got {}'
107107
''.format(length_in))
108108

109-
try:
110-
# TODO: always use this when numpy >= 1.10 can be assumed
111-
param = np.array(param, dtype=object, copy=True, ndmin=1)
112-
nonconv_list = list(np.broadcast_to(param, (length,)))
113-
except AttributeError:
114-
# numpy.broadcast_to not available
115-
if np.isscalar(param):
116-
# Try this first, will work better with iterable input like '10'
117-
nonconv_list = [param] * length
118-
else:
119-
try:
120-
param_len = len(param)
121-
except TypeError:
122-
# Not a sequence -> single parameter
123-
nonconv_list = [param] * length
124-
else:
125-
if param_len == 1:
126-
nonconv_list = list(param) * length
127-
elif param_len == length:
128-
nonconv_list = list(param)
129-
else:
130-
raise ValueError('sequence `param` has length {}, '
131-
'expected {}'.format(param_len, length))
109+
param = np.array(param, dtype=object, copy=True, ndmin=1)
110+
nonconv_list = list(np.broadcast_to(param, (length,)))
132111

133112
if len(nonconv_list) != length:
134113
raise ValueError('sequence `param` has length {}, expected {}'

odl/util/npy_compat.py

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,7 @@
1212
import numpy as np
1313

1414

15-
__all__ = ('broadcast_to', 'moveaxis')
16-
17-
18-
# TODO: Remove when Numpy 1.10 is an ODL dependency
19-
def broadcast_to(array, shape):
20-
"""Broadcast an array to a new shape.
21-
22-
This function is a backport of `numpy.broadcast_to` introduced in
23-
NumPy 1.10.
24-
25-
See Also
26-
--------
27-
numpy.broadcast_to
28-
"""
29-
array = np.asarray(array)
30-
try:
31-
return np.broadcast_to(array, shape)
32-
except AttributeError:
33-
# The above requires numpy 1.10, fallback impl else
34-
shape = [m if n == 1 and m != 1 else 1
35-
for n, m in zip(array.shape, shape)]
36-
return array + np.zeros(shape, dtype=array.dtype)
15+
__all__ = ('moveaxis', 'flip')
3716

3817

3918
# TODO: Remove when Numpy 1.11 is an ODL dependency

odl/util/testutils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,8 @@ def noise_array(space):
327327
return np.array([noise_array(si) for si in space])
328328
else:
329329
if space.dtype == bool:
330-
arr = np.random.randint(0, 2, size=space.shape, dtype=bool)
330+
# TODO(kohr-h): use `randint(..., dtype=bool)` from Numpy 1.11 on
331+
arr = np.random.randint(0, 2, size=space.shape).astype(bool)
331332
elif np.issubdtype(space.dtype, np.unsignedinteger):
332333
arr = np.random.randint(0, 10, space.shape)
333334
elif np.issubdtype(space.dtype, np.signedinteger):

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
future >=0.14
2-
numpy >=1.9,!=1.14.0
2+
numpy >=1.10,!=1.14.0
33
scipy >=0.14

0 commit comments

Comments
 (0)