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

Feature/cython 3 0 #36

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools", "wheel", "cython>=3.0.3"]
build-backend = "setuptools.build_meta"
16 changes: 16 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,32 @@
import io
from distutils.core import setup

# deciding to use cython or not based on its successful import
USE_CYTHON : bool = True
try:
from Cython.Build import cythonize
except ModuleNotFoundError:
print('unable to retrieve cython, will resort to pure python installation')
USE_CYTHON = False

# load the version from version.py
version = {}
with open("similaritymeasures/version.py") as fp:
exec(fp.read(), version)

# based on the option of using cython or not the ext_modules variable is set
if USE_CYTHON:
ext_modules = cythonize('similaritymeasures/similaritymeasures.py', language='c++')
else:
ext_modules = []

setup(
name='similaritymeasures',
version=version["__version__"],
author='Charles Jekel',
author_email='cjekel@gmail.com',
packages=['similaritymeasures'],
ext_modules=ext_modules,
url='https://github.com/cjekel/similarity_measures',
license='MIT License',
description='Quantify the difference between two arbitrary curves in space', # noqa E501
Expand All @@ -22,5 +37,6 @@
install_requires=[
"numpy >= 1.14.0",
"scipy >= 0.19.0",
"cython >= 3.0.3"
],
)
43 changes: 43 additions & 0 deletions similaritymeasures/similaritymeasures.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import division
import numpy as np
from scipy.spatial import distance

import cython
# MIT License
#
# Copyright (c) 2018,2019 Charles Jekel
Expand All @@ -24,6 +26,8 @@
# SOFTWARE.


@cython.boundscheck(False)
@cython.wraparound(False)
def poly_area(x, y):
r"""
A function that computes the polygonal area via the shoelace formula.
Expand Down Expand Up @@ -57,6 +61,8 @@ def poly_area(x, y):
return 0.5*np.abs(np.dot(x, np.roll(y, 1))-np.dot(y, np.roll(x, 1)))


@cython.boundscheck(False)
@cython.wraparound(False)
def is_simple_quad(ab, bc, cd, da):
r"""
Returns True if a quadrilateral is simple
Expand Down Expand Up @@ -98,6 +104,8 @@ def is_simple_quad(ab, bc, cd, da):
return sum(crossTF) > 2


@cython.boundscheck(False)
@cython.wraparound(False)
def makeQuad(x, y):
r"""
Calculate the area from the x and y locations of a quadrilateral
Expand Down Expand Up @@ -165,6 +173,8 @@ def makeQuad(x, y):
return area


@cython.boundscheck(False)
@cython.wraparound(False)
def get_arc_length(dataset):
r"""
Obtain arc length distances between every point in 2-D space
Expand Down Expand Up @@ -203,6 +213,8 @@ def get_arc_length(dataset):
return arcLength, arcLengths


@cython.boundscheck(False)
@cython.wraparound(False)
def area_between_two_curves(exp_data, num_data):
r"""
Calculates the area between two curves.
Expand Down Expand Up @@ -252,6 +264,9 @@ def area_between_two_curves(exp_data, num_data):
#
# then you can calculate the area as
# area = area_between_two_curves(exp_data, num_data)
i = cython.declare(cython.int)
n_exp = cython.declare(cython.int)
n_num = cython.declare(cython.int)

n_exp = len(exp_data)
n_num = len(num_data)
Expand Down Expand Up @@ -300,6 +315,8 @@ def area_between_two_curves(exp_data, num_data):
return np.sum(area)


@cython.boundscheck(False)
@cython.wraparound(False)
def get_length(x, y, norm_seg_length=True):
r"""
Compute arc lengths of an x y curve.
Expand Down Expand Up @@ -331,6 +348,8 @@ def get_length(x, y, norm_seg_length=True):
>>> le, le_total, le_cum = get_length(x, y)

"""
i = cython.declare(cython.int)
n = cython.declare(cython.int)
n = len(x)

if norm_seg_length:
Expand All @@ -357,6 +376,8 @@ def get_length(x, y, norm_seg_length=True):
return le, np.sum(le), l_sum


@cython.boundscheck(False)
@cython.wraparound(False)
def curve_length_measure(exp_data, num_data):
r"""
Compute the curve length based distance between two curves.
Expand Down Expand Up @@ -430,6 +451,8 @@ def curve_length_measure(exp_data, num_data):
return np.sqrt(np.sum(r_sq))


@cython.boundscheck(False)
@cython.wraparound(False)
def frechet_dist(exp_data, num_data, p=2):
r"""
Compute the discrete Frechet distance
Expand Down Expand Up @@ -490,6 +513,10 @@ def frechet_dist(exp_data, num_data, p=2):
>>> df = frechet_dist(exp_data, num_data)

"""
i = cython.declare(cython.int)
j = cython.declare(cython.int)
n = cython.declare(cython.int)
m = cython.declare(cython.int)
n = len(exp_data)
m = len(num_data)
c = distance.cdist(exp_data, num_data, metric='minkowski', p=p)
Expand All @@ -507,6 +534,8 @@ def frechet_dist(exp_data, num_data, p=2):
return ca[n-1, m-1]


@cython.boundscheck(False)
@cython.wraparound(False)
def normalizeTwoCurves(x, y, w, z):
"""
Normalize two curves for PCM method.
Expand Down Expand Up @@ -561,6 +590,8 @@ def normalizeTwoCurves(x, y, w, z):
return xi, eta, xiP, etaP


@cython.boundscheck(False)
@cython.wraparound(False)
def pcm(exp_data, num_data, norm_seg_length=False):
"""
Compute the Partial Curve Mapping area.
Expand Down Expand Up @@ -677,6 +708,8 @@ def pcm(exp_data, num_data, norm_seg_length=False):
return np.min(pcm_dists)


@cython.boundscheck(False)
@cython.wraparound(False)
def dtw(exp_data, num_data, metric='euclidean', **kwargs):
r"""
Compute the Dynamic Time Warping distance.
Expand Down Expand Up @@ -782,6 +815,8 @@ def dtw(exp_data, num_data, metric='euclidean', **kwargs):
>>> r, d = dtw(exp_data, num_data, metric='cityblock')

"""
i = cython.declare(cython.int)
j = cython.declare(cython.int)
c = distance.cdist(exp_data, num_data, metric=metric, **kwargs)

d = np.zeros(c.shape)
Expand All @@ -797,6 +832,8 @@ def dtw(exp_data, num_data, metric='euclidean', **kwargs):
return d[-1, -1], d


@cython.boundscheck(False)
@cython.wraparound(False)
def dtw_path(d):
r"""
Calculates the optimal DTW path from a given DTW cumulative distance
Expand Down Expand Up @@ -861,6 +898,8 @@ def dtw_path(d):
>>> plt.show()

"""
i = cython.declare(cython.int)
j = cython.declare(cython.int)
path = []
i, j = d.shape
i = i - 1
Expand Down Expand Up @@ -888,6 +927,8 @@ def dtw_path(d):
return path[::-1]


@cython.boundscheck(False)
@cython.wraparound(False)
def mae(exp_data, num_data):
"""
Compute the Mean Absolute Error (MAE).
Expand All @@ -913,6 +954,8 @@ def mae(exp_data, num_data):
return np.mean(c)


@cython.boundscheck(False)
@cython.wraparound(False)
def mse(exp_data, num_data):
"""
Compute the Mean Squared Error (MAE).
Expand Down