8000 Fix #5693: Implemented is_sorted in C by mdboom · Pull Request #5719 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Fix #5693: Implemented is_sorted in C #5719

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

Merged
merged 2 commits into from
Dec 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations 10000
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions lib/matplotlib/lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from matplotlib.markers import (
CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN,
CARETLEFTBASE, CARETRIGHTBASE, CARETUPBASE, CARETDOWNBASE)
from matplotlib import _path


def segment_hits(cx, cy, x, y, radius):
Expand Down Expand Up @@ -702,9 +703,7 @@ def set_transform(self, t):
def _is_sorted(self, x):
"""return True if x is sorted in ascending order"""
# We don't handle the monotonically decreasing case.
if len(x) < 2:
return True
return np.nanmin(x[1:] - x[:-1]) >= 0
return _path.is_sorted(x)

@allow_rasterization
def draw(self, renderer):
Expand Down
5 changes: 3 additions & 2 deletions lib/matplotlib/tests/test_lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,9 @@ def test_marker_fill_styles():
def test_nan_is_sorted():
# Exercises issue from PR #2744 (NaN throwing warning in _is_sorted)
line = mlines.Line2D([],[])
assert_true(line._is_sorted(np.array([1,2,3])))
assert_true(not line._is_sorted(np.array([1,np.nan,3])))
assert_true(line._is_sorted(np.array([1, 2, 3])))
assert_true(line._is_sorted(np.array([1, np.nan, 3])))
assert_true(not line._is_sorted([3, 5] + [np.nan] * 100 + [0, 2]))


if __name__ == '__main__':
Expand Down
66 changes: 66 additions & 0 deletions src/_path.h
Original file line number Diff line number Diff line change
Expand Up @@ -1183,4 +1183,70 @@ int convert_to_string(PathIterator &path,

}

template<class T>
struct _is_sorted
{
bool operator()(PyArrayObject *array)
{
npy_intp size;
npy_intp i;
T last_value;
T current_value;

size = PyArray_DIM(array, 0);

for (i = 0; i < size; ++i) {
last_value = *((T *)PyArray_GETPTR1(array, i));
if (std::isfinite(last_value)) {
break;
}
}

if (i == size) {
// The whole array is non-finite
return false;
}

for (; i < size; ++i) {
current_value = *((T *)PyArray_GETPTR1(array, i));
if (std::isfinite(current_value)) {
if (current_value < last_value) {
return false;
}
last_value = current_value;
}
}

return true;
}
};


template<class T>
struct _is_sorted_int
{
bool operator()(PyArrayObject *array)
{
npy_intp size;
npy_intp i;
T last_value;
T current_value;

size = PyArray_DIM(array, 0);

last_value = *((T *)PyArray_GETPTR1(array, 0));

for (i = 1; i < size; ++i) {
current_value = *((T *)PyArray_GETPTR1(array, i));
if (current_value < last_value) {
return false;
}
last_value = current_value;
}

return true;
}
};


#endif
86 changes: 86 additions & 0 deletions src/_path_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,91 @@ static PyObject *Py_convert_to_string(PyObject *self, PyObject *args, PyObject *
return result;
}


const char *Py_is_sorted__doc__ = "is_sorted(array)\n\n"
"Returns True if 1-D array is monotonically increasing, ignoring NaNs\n";

static PyObject *Py_is_sorted(PyObject *self, PyObject *obj)
{
npy_intp size;
bool result;

PyArrayObject *array = (PyArrayObject *)PyArray_FromAny(
obj, NULL, 1, 1, 0, NULL);

if (array == NULL) {
return NULL;
}

size = PyArray_DIM(array, 0);

if (size < 2) {
Py_DECREF(array);
Py_RETURN_TRUE;
}

/* Handle just the most common types here, otherwise coerce to
double */
switch(PyArray_TYPE(array)) {
case NPY_INT:
{
_is_sorted_int<npy_int> is_sorted;
result = is_sorted(array);
}
break;

case NPY_LONG:
{
_is_sorted_int<npy_long> is_sorted;
result = is_sorted(array);
}
break;

case NPY_LONGLONG:
{
_is_sorted_int<npy_longlong> is_sorted;
result = is_sorted(array);
}
break;

case NPY_FLOAT:
{
_is_sorted<npy_float> is_sorted;
result = is_sorted(array);
}
break;

case NPY_DOUBLE:
{
< 8000 /td> _is_sorted<npy_double> is_sorted;
result = is_sorted(array);
}
break;

default:
{
Py_DECREF(array);
array = (PyArrayObject *)PyArray_FromObject(obj, NPY_DOUBLE, 1, 1);

if (array == NULL) {
return NULL;
}

_is_sorted<npy_double> is_sorted;
result = is_sorted(array);
}
}

Py_DECREF(array);

if (result) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
}


extern "C" {

static PyMethodDef module_functions[] = {
Expand All @@ -745,6 +830,7 @@ extern "C" {
{"convert_path_to_polygons", (PyCFunction)Py_convert_path_to_polygons, METH_VARARGS, Py_convert_path_to_polygons__doc__},
{"cleanup_path", (PyCFunction)Py_cleanup_path, METH_VARARGS, Py_cleanup_path__doc__},
{"convert_to_string", (PyCFunction)Py_convert_to_string, METH_VARARGS, Py_convert_to_string__doc__},
{"is_sorted", (PyCFunction)Py_is_sorted, METH_O, Py_is_sorted__doc__},
{NULL}
};

Expand Down
0