4
#include "structmember.h"
5
#include "numpy/arrayobject.h"
6
#include "numpy/ufuncobject.h"
8
#define SAFE_FROMARRAY_1D(a, type) \
9
((a) == NULL) ? (a) : PyArray_FROMANY(a, type, 1, 1, NPY_IN_ARRAY)
12
PyMODINIT_FUNC init_speedups(void);
13
//static PyObject *scatterplot_gather_points(PyObject *args, PyObject *kwargs);
17
// Given a tuple or list of indices and an array length, returns a new array of
18
// the given length with value 1 at each indices in the list of indices, and 0
20
// The caller must deallocate the array when they are done.
21
// If selections is NULL or arrayLen is 0, then a null pointer is returned.
22
char *create_mirror_mask_array(PyObject *selections, int arrayLen)
24
if ((selections != NULL) && (arrayLen > 0) && (PySequence_Length(selections) > 0))
27
char *mirror = new char[arrayLen];
28
memset(mirror, 0, arrayLen);
29
int numIndices = PySequence_Length(selections);
31
for (int i=0; i < numIndices; i++)
33
tmp = PyTuple_GetItem(selections, i);
34
mirror[PyInt_AsLong(tmp)] = 1;
46
* Scatterplot speedups
49
static char scatterplot_gather_points_doc[] = \
50
"Takes index and value arrays, masks, and optional selection arrays, \n" \
51
"and returns the list of points and corresponding selection mask for \n" \
56
"index : float array (1D) \n" \
57
"index_low : float or None\n" \
58
" The minimum acceptable value in the index array\n" \
59
"index_high : float or None \n" \
60
" The maximum acceptable value in the index array\n" \
61
"value : float array (1D) \n" \
62
"value_low : float or None\n" \
63
" The minimum acceptable value in the value array\n" \
64
"value_high : float or None \n" \
65
" The maximum acceptable value in the value array\n" \
67
"Optional Parameters\n" \
68
"-------------------\n" \
69
"index_mask : bool or int array (1D) \n" \
70
" A mask that indicates which index points should be used\n" \
71
"index_sel : sequence of ints \n" \
72
" A list/tuple/array of indices of selected positions in the index array\n " \
73
"index_sel_mask : array of ints or bools\n" \
74
" An mask array with True values indicating which points are selected\n" \
75
"value_mask : bool or int array (1D) \n" \
76
" A mask that indicates which value points should be used\n" \
77
"value_sel : sequence of ints \n" \
78
" A list/tuple/array of indices of selected positions in the value array\n " \
79
"value_sel_mask : array of ints or bools\n" \
80
" An mask array with True values indicating which points are selected\n" \
84
"points : float array (Nx2) \n " \
85
" The points that match all the masking criteria \n" \
86
"sel_mask : bool array (1D) \n " \
87
" Mask indicating which indices in **points** are selected \n" \
90
#define DEBUG_SPEEDUP 0
92
static PyObject *scatterplot_gather_points(PyObject *self, PyObject* args, PyObject* kwargs)
94
PyObject *index, *index_mask, *index_sel, *index_sel_mask;
95
PyObject *value, *value_mask, *value_sel, *value_sel_mask;
98
index = index_mask = index_sel = index_sel_mask = NULL;
99
value = value_mask = value_sel = value_sel_mask = NULL;
101
// Stores the points and selection array while we're iterating over the input
102
npy_float *points = NULL;
103
npy_bool *points_mask = NULL;
105
PyObject *np_points, *np_points_mask, *returnval = NULL;
107
double index_low, index_high, value_low, value_high;
108
unsigned int numValidPts = 0;
111
int numIndex, numValue;
112
char *index_sel_mirror, *value_sel_mirror;
113
int numpoints; // The number of points to iterate over in the input arrays
115
static char *keywords[] = {"index", "index_low", "index_high",
116
"value", "value_low", "value_high",
117
"index_mask", "index_sel", "index_sel_mask",
118
"value_mask", "value_sel", "value_sel_mask", NULL};
120
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OddOdd|OOOOOO", keywords,
121
&index, &index_low, &index_high,
122
&value, &value_low, &value_high,
123
&index_mask, &index_sel, &index_sel_mask,
124
&value_mask, &value_sel, &value_sel_mask))
128
printf("Parsed arguments\n");
131
index = PyArray_FROMANY(index, NPY_DOUBLE, 1, 1, NPY_IN_ARRAY);
134
value = PyArray_FROMANY(value, NPY_DOUBLE, 1, 1, NPY_IN_ARRAY);
139
printf("Got index and value\n");
142
index_mask = SAFE_FROMARRAY_1D(index_mask, NPY_BOOL);
143
index_sel = SAFE_FROMARRAY_1D(index_sel, NPY_INT);
144
index_sel_mask = SAFE_FROMARRAY_1D(index_sel_mask, NPY_BOOL);
146
value_mask = SAFE_FROMARRAY_1D(value_mask, NPY_BOOL);
147
value_sel = SAFE_FROMARRAY_1D(value_sel, NPY_INT);
148
value_sel_mask = SAFE_FROMARRAY_1D(value_sel_mask, NPY_BOOL);
150
numIndex = PyArray_DIM(index, 0);
151
numValue = PyArray_DIM(value, 0);
153
index_sel_mirror = create_mirror_mask_array(index_sel, numIndex);
154
value_sel_mirror = create_mirror_mask_array(value_sel, numValue);
157
if ((index_sel_mirror != NULL) || (value_sel_mirror != NULL))
158
printf("Created mirrors\n");
160
printf("Created empty mirrors\n");
163
// Determine the total number of points to iterate over in the input arrays
164
// based on the shorter of index or value
165
numpoints = PySequence_Length(index);
166
if (PySequence_Length(value) < numpoints)
167
numpoints = PySequence_Length(value);
169
// Create a new array for the list of good points and selections into that array
170
points = new npy_float[numpoints * 2];
173
printf("Created points array\n");
176
if ((index_sel != NULL) || (index_sel_mask != NULL) ||
177
(value_sel != NULL) || (value_sel_mask != NULL))
179
points_mask = new npy_bool[numpoints];
181
printf("Created points_mask array\n");
186
// Iterate over the list of x,y positions and check to see if they
187
// should be copied into the output list
188
for (int i=0; i < numpoints; i++)
190
x = *((double *) (PyArray_GETPTR1(index, i)));
191
y = *((double *) (PyArray_GETPTR1(value, i)));
193
if (((index_mask != NULL) && (*(npy_bool*)PyArray_GETPTR1(index_mask, i) == 0)) ||
194
((value_mask != NULL) && (*(npy_bool*)PyArray_GETPTR1(value_mask, i) == 0)))
197
if (isnan(x) || isnan(y))
200
if ((x < index_low) || (x > index_high) ||
201
(y < value_low) || (y > value_high))
204
points[numValidPts * 2] = x;
205
points[numValidPts * 2 + 1] = y;
207
if (((index_sel_mirror != NULL) && (index_sel_mirror[i] == 1)) ||
208
((value_sel_mirror != NULL) && (value_sel_mirror[i] == 1)) ||
209
((index_sel_mask != NULL) &&
210
(*(npy_bool*)PyArray_GETPTR1(index_sel_mask, i) == 1)) ||
211
((value_sel_mask != NULL) &&
212
(*(npy_bool*)PyArray_GETPTR1(value_sel_mask, i) == 1)))
214
points_mask[numValidPts] = 1;
216
else if (points_mask != NULL)
218
points_mask[numValidPts] = 0;
225
printf("Finished main loop\n");
228
// Copy the valid points into a compact array of the right length
230
dims[0] = numValidPts;
232
np_points = PyArray_SimpleNew(2, dims, NPY_DOUBLE);
233
for (int i=0; i < numValidPts; i++)
235
*((npy_double*) PyArray_GETPTR2(np_points, i, 0)) = points[i*2];
236
*((npy_double*) PyArray_GETPTR2(np_points, i, 1)) = points[i*2 + 1];
239
if (points_mask != NULL)
241
npy_intp maskdims[1];
242
maskdims[0] = numValidPts;
243
np_points_mask = PyArray_SimpleNew(1, maskdims, NPY_BOOL);
244
for (int i=0; i< numValidPts; i++)
245
*(npy_bool*)(PyArray_GETPTR1(np_points_mask, i)) = points_mask[i];
250
np_points_mask = Py_None;
254
printf("Compacted array\n");
257
returnval = Py_BuildValue("(OO)", np_points, np_points_mask);
259
if (index_sel_mirror != NULL)
260
delete[] index_sel_mirror;
261
if (value_sel_mirror != NULL)
262
delete[] value_sel_mirror;
265
if (points_mask != NULL)
266
delete[] points_mask;
268
Py_DECREF(np_points);
269
Py_DECREF(np_points_mask);
272
printf("Built return value and DECREFed\n");
277
Py_XDECREF(index_mask);
278
Py_XDECREF(index_sel);
279
Py_XDECREF(index_sel_mask);
281
Py_XDECREF(value_mask);
282
Py_XDECREF(value_sel);
283
Py_XDECREF(value_sel_mask);
286
printf("About to return\n");
293
static PyMethodDef speedups_methods[] = {
294
{"scatterplot_gather_points", (PyCFunction)scatterplot_gather_points,
295
METH_VARARGS | METH_KEYWORDS,
296
scatterplot_gather_points_doc},
297
{NULL, NULL, 0, NULL}
300
PyMODINIT_FUNC init_speedups(void)
302
PyObject *module = Py_InitModule3("_speedups", speedups_methods,
303
"Fast array range/NaN checking to accelerate plotting");