Skip to content

Commit

Permalink
pythran
Browse files Browse the repository at this point in the history
  • Loading branch information
martibosch committed Jul 1, 2019
1 parent a3e5742 commit 05537f5
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 39 deletions.
35 changes: 19 additions & 16 deletions utils/__init__.py → pylandstats/compute.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import numpy as np
from numba import pycc

cc = pycc.CC('pylandstats_compute')


@cc.export('compute_adjacency_arr', 'uint32[:,:,:](uint32[:,:], int32)')
def compute_adjacency_arr(padded_arr, num_classes):
# flat-array approach to pixel adjacency from link below:
# https://ilovesymposia.com/2016/12/20/numba-in-the-real-world/
# the first axis of `adjacency_arr` is of fixed size of 2 and serves to
# distinguish between vertical and horizontal adjacencies (we could also
# use a tuple of two 2-D arrays)
adjacency_arr = np.zeros((2, num_classes + 1, num_classes + 1),
dtype=np.uint32)
num_cols = padded_arr.shape[1]
# adjacency_arr = np.zeros((2, num_classes + 1, num_classes + 1),
# dtype=np.uint32)
num_cols_adjacency = num_classes + 1
horizontal_adjacency_arr = np.zeros(
num_cols_adjacency * num_cols_adjacency, dtype=np.uint32)
vertical_adjacency_arr = np.zeros(num_cols_adjacency * num_cols_adjacency,
dtype=np.uint32)
num_cols_pixel = padded_arr.shape[1]
flat_arr = padded_arr.ravel()
# steps_to_neighbours as argument to distinguish between vertical/
# horizontal adjacencies
# steps_to_neighbours = [1, num_cols, -1, -num_cols]
horizontal_neighbours = [1, -1]
vertical_neighbours = [num_cols, -num_cols]
start = num_cols + 1
vertical_neighbours = [num_cols_pixel, -num_cols_pixel]
start = num_cols_pixel + 1
end = len(flat_arr) - start
for i in range(start, end):
class_i = flat_arr[i]
Expand All @@ -33,12 +34,14 @@ def compute_adjacency_arr(padded_arr, num_classes):
# adjacency_arr[1, class_i, class_above] += 1
# adjacency_arr[1, class_i, class_below] += 1
for neighbour in horizontal_neighbours:
adjacency_arr[0, class_i, flat_arr[i + neighbour]] += 1
# adjacency_arr[0, class_i, flat_arr[i + neighbour]] += 1
horizontal_adjacency_arr[class_i + num_cols_adjacency *
flat_arr[i + neighbour]] += 1
for neighbour in vertical_neighbours:
adjacency_arr[1, class_i, flat_arr[i + neighbour]] += 1

return adjacency_arr

# adjacency_arr[1, class_i, flat_arr[i + neighbour]] += 1
vertical_adjacency_arr[class_i + num_cols_adjacency *
flat_arr[i + neighbour]] += 1

if __name__ == '__main__':
cc.compile()
return np.stack(
(horizontal_adjacency_arr, vertical_adjacency_arr)).reshape(
(2, num_cols_adjacency, num_cols_adjacency))
1 change: 1 addition & 0 deletions pylandstats/compute.pythran
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export compute_adjacency_arr(uint32[:,:], int)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[build-system]
requires = ['setuptools>=40.8.0', 'wheel', 'numba', 'numpy']
requires = ['setuptools>=40.8.0', 'wheel', 'pythran', 'numpy']
29 changes: 8 additions & 21 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# coding=utf-8

from distutils.command.build_ext import build_ext
from distutils.sysconfig import customize_compiler
from io import open # compatible enconding parameter
from os import path

from setuptools import find_packages, setup
from utils import cc
from pythran.dist import PythranBuildExt, PythranExtension
from setuptools import dist, find_packages, setup

__version__ = '0.5.0'

Expand Down Expand Up @@ -39,21 +37,8 @@
x.strip().replace('git+', '') for x in all_reqs if x.startswith('git+')
]


# Avoid a gcc warning (see https://stackoverflow.com/questions/8106258/cc1plus-
# warning-command-line-option-wstrict-prototypes-is-valid-for-ada-c-o):
# cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid
# for C/ObjC but not for C++
# See also: https://github.com/numba/numba/issues/3361
class BuildExt(build_ext):
def build_extensions(self):
customize_compiler(self.compiler)
try:
self.compiler.compiler_so.remove("-Wstrict-prototypes")
except (AttributeError, ValueError):
pass
build_ext.build_extensions(self)

# This is required to be able to use pythran in setup.py
dist.Distribution(dict(setup_requires='pythran'))

setup(
name='pylandstats',
Expand All @@ -71,6 +56,8 @@ def build_extensions(self):
install_requires=install_requires,
extras_require={'geo': geo},
dependency_links=dependency_links,
cmdclass={'build_ext': BuildExt},
ext_modules=[cc.distutils_extension()],
ext_modules=[
PythranExtension('pylandstats_compute', ['pylandstats/compute.py'])
],
cmdclass={'build_ext': PythranBuildExt},
)
5 changes: 4 additions & 1 deletion tests/test_pylandstats.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,9 +405,12 @@ def test_multilandscape_metric_kws(self):
else:
self.assertLess(class_metrics['total_area'],
class_metrics_kws['total_area'])
# we need quite some tolerance because pixel resolutions in
# raster files might be wierd float values, e.g., 99.13213
# instead of 100 (meters)
self.assertLessEqual(
class_metrics['total_edge'],
class_metrics_kws['total_edge'] + .0004)
1.01 * class_metrics_kws['total_edge'])

def test_multilandscape_plot_metrics(self):
ml = self.InstantiableMultiLandscape(self.landscape_fps,
Expand Down

0 comments on commit 05537f5

Please sign in to comment.