1
|
|
/*
|
2
|
|
Provide multidimensional arrays as a basic object type in python.
|
3
|
|
|
4
|
|
Based on Original Numeric implementation
|
5
|
|
Copyright (c) 1995, 1996, 1997 Jim Hugunin, hugunin@mit.edu
|
6
|
|
|
7
|
|
with contributions from many Numeric Python developers 1995-2004
|
8
|
|
|
9
|
|
Heavily modified in 2005 with inspiration from Numarray
|
10
|
|
|
11
|
|
by
|
12
|
|
|
13
|
|
Travis Oliphant, oliphant@ee.byu.edu
|
14
|
|
Brigham Young University
|
15
|
|
|
16
|
|
|
17
|
|
maintainer email: oliphant.travis@ieee.org
|
18
|
|
|
19
|
|
Numarray design (which provided guidance) by
|
20
|
|
Space Science Telescope Institute
|
21
|
|
(J. Todd Miller, Perry Greenfield, Rick White)
|
22
|
|
*/
|
23
|
|
#define PY_SSIZE_T_CLEAN
|
24
|
|
#include <Python.h>
|
25
|
|
#include "structmember.h"
|
26
|
|
|
27
|
|
/*#include <stdio.h>*/
|
28
|
|
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
|
29
|
|
#define _MULTIARRAYMODULE
|
30
|
|
#include "numpy/arrayobject.h"
|
31
|
|
#include "numpy/arrayscalars.h"
|
32
|
|
|
33
|
|
#include "npy_config.h"
|
34
|
|
|
35
|
|
#include "npy_pycompat.h"
|
36
|
|
|
37
|
|
#include "common.h"
|
38
|
|
|
39
|
|
#include "number.h"
|
40
|
|
#include "usertypes.h"
|
41
|
|
#include "arraytypes.h"
|
42
|
|
#include "scalartypes.h"
|
43
|
|
#include "arrayobject.h"
|
44
|
|
#include "conversion_utils.h"
|
45
|
|
#include "ctors.h"
|
46
|
|
#include "dtypemeta.h"
|
47
|
|
#include "methods.h"
|
48
|
|
#include "descriptor.h"
|
49
|
|
#include "iterators.h"
|
50
|
|
#include "mapping.h"
|
51
|
|
#include "getset.h"
|
52
|
|
#include "sequence.h"
|
53
|
|
#include "npy_buffer.h"
|
54
|
|
#include "array_assign.h"
|
55
|
|
#include "alloc.h"
|
56
|
|
#include "mem_overlap.h"
|
57
|
|
#include "numpyos.h"
|
58
|
|
#include "strfuncs.h"
|
59
|
|
|
60
|
|
#include "binop_override.h"
|
61
|
|
#include "array_coercion.h"
|
62
|
|
|
63
|
|
/*NUMPY_API
|
64
|
|
Compute the size of an array (in number of items)
|
65
|
|
*/
|
66
|
|
NPY_NO_EXPORT npy_intp
|
67
|
1
|
PyArray_Size(PyObject *op)
|
68
|
|
{
|
69
|
1
|
if (PyArray_Check(op)) {
|
70
|
1
|
return PyArray_SIZE((PyArrayObject *)op);
|
71
|
|
}
|
72
|
|
else {
|
73
|
|
return 0;
|
74
|
|
}
|
75
|
|
}
|
76
|
|
|
77
|
|
/*NUMPY_API
|
78
|
|
*
|
79
|
|
* Precondition: 'arr' is a copy of 'base' (though possibly with different
|
80
|
|
* strides, ordering, etc.). This function sets the UPDATEIFCOPY flag and the
|
81
|
|
* ->base pointer on 'arr', so that when 'arr' is destructed, it will copy any
|
82
|
|
* changes back to 'base'. DEPRECATED, use PyArray_SetWritebackIfCopyBase
|
83
|
|
*
|
84
|
|
* Steals a reference to 'base'.
|
85
|
|
*
|
86
|
|
* Returns 0 on success, -1 on failure.
|
87
|
|
*/
|
88
|
|
NPY_NO_EXPORT int
|
89
|
0
|
PyArray_SetUpdateIfCopyBase(PyArrayObject *arr, PyArrayObject *base)
|
90
|
|
{
|
91
|
|
int ret;
|
92
|
|
/* 2017-Nov -10 1.14 (for PyPy only) */
|
93
|
|
/* 2018-April-21 1.15 (all Python implementations) */
|
94
|
0
|
if (DEPRECATE("PyArray_SetUpdateIfCopyBase is deprecated, use "
|
95
|
|
"PyArray_SetWritebackIfCopyBase instead, and be sure to call "
|
96
|
|
"PyArray_ResolveWritebackIfCopy before the array is deallocated, "
|
97
|
|
"i.e. before the last call to Py_DECREF. If cleaning up from an "
|
98
|
|
"error, PyArray_DiscardWritebackIfCopy may be called instead to "
|
99
|
|
"throw away the scratch buffer.") < 0)
|
100
|
|
return -1;
|
101
|
0
|
ret = PyArray_SetWritebackIfCopyBase(arr, base);
|
102
|
0
|
if (ret >=0) {
|
103
|
0
|
PyArray_ENABLEFLAGS(arr, NPY_ARRAY_UPDATEIFCOPY);
|
104
|
|
PyArray_CLEARFLAGS(arr, NPY_ARRAY_WRITEBACKIFCOPY);
|
105
|
|
}
|
106
|
|
return ret;
|
107
|
|
}
|
108
|
|
|
109
|
|
/*NUMPY_API
|
110
|
|
*
|
111
|
|
* Precondition: 'arr' is a copy of 'base' (though possibly with different
|
112
|
|
* strides, ordering, etc.). This function sets the WRITEBACKIFCOPY flag and the
|
113
|
|
* ->base pointer on 'arr', call PyArray_ResolveWritebackIfCopy to copy any
|
114
|
|
* changes back to 'base' before deallocating the array.
|
115
|
|
*
|
116
|
|
* Steals a reference to 'base'.
|
117
|
|
*
|
118
|
|
* Returns 0 on success, -1 on failure.
|
119
|
|
*/
|
120
|
|
NPY_NO_EXPORT int
|
121
|
1
|
PyArray_SetWritebackIfCopyBase(PyArrayObject *arr, PyArrayObject *base)
|
122
|
|
{
|
123
|
1
|
if (base == NULL) {
|
124
|
0
|
PyErr_SetString(PyExc_ValueError,
|
125
|
|
"Cannot WRITEBACKIFCOPY to NULL array");
|
126
|
0
|
return -1;
|
127
|
|
}
|
128
|
1
|
if (PyArray_BASE(arr) != NULL) {
|
129
|
0
|
PyErr_SetString(PyExc_ValueError,
|
130
|
|
"Cannot set array with existing base to WRITEBACKIFCOPY");
|
131
|
0
|
goto fail;
|
132
|
|
}
|
133
|
1
|
if (PyArray_FailUnlessWriteable(base, "WRITEBACKIFCOPY base") < 0) {
|
134
|
|
goto fail;
|
135
|
|
}
|
136
|
|
|
137
|
|
/*
|
138
|
|
* Any writes to 'arr' will magically turn into writes to 'base', so we
|
139
|
|
* should warn if necessary.
|
140
|
|
*/
|
141
|
1
|
if (PyArray_FLAGS(base) & NPY_ARRAY_WARN_ON_WRITE) {
|
142
|
0
|
PyArray_ENABLEFLAGS(arr, NPY_ARRAY_WARN_ON_WRITE);
|
143
|
|
}
|
144
|
|
|
145
|
|
/*
|
146
|
|
* Unlike PyArray_SetBaseObject, we do not compress the chain of base
|
147
|
|
* references.
|
148
|
|
*/
|
149
|
1
|
((PyArrayObject_fields *)arr)->base = (PyObject *)base;
|
150
|
1
|
PyArray_ENABLEFLAGS(arr, NPY_ARRAY_WRITEBACKIFCOPY);
|
151
|
1
|
PyArray_CLEARFLAGS(base, NPY_ARRAY_WRITEABLE);
|
152
|
|
|
153
|
1
|
return 0;
|
154
|
|
|
155
|
0
|
fail:
|
156
|
0
|
Py_DECREF(base);
|
157
|
|
return -1;
|
158
|
|
}
|
159
|
|
|
160
|
|
/*NUMPY_API
|
161
|
|
* Sets the 'base' attribute of the array. This steals a reference
|
162
|
|
* to 'obj'.
|
163
|
|
*
|
164
|
|
* Returns 0 on success, -1 on failure.
|
165
|
|
*/
|
166
|
|
NPY_NO_EXPORT int
|
167
|
1
|
PyArray_SetBaseObject(PyArrayObject *arr, PyObject *obj)
|
168
|
|
{
|
169
|
1
|
if (obj == NULL) {
|
170
|
0
|
PyErr_SetString(PyExc_ValueError,
|
171
|
|
"Cannot set the NumPy array 'base' "
|
172
|
|
"dependency to NULL after initialization");
|
173
|
0
|
return -1;
|
174
|
|
}
|
175
|
|
/*
|
176
|
|
* Allow the base to be set only once. Once the object which
|
177
|
|
* owns the data is set, it doesn't make sense to change it.
|
178
|
|
*/
|
179
|
1
|
if (PyArray_BASE(arr) != NULL) {
|
180
|
0
|
Py_DECREF(obj);
|
181
|
0
|
PyErr_SetString(PyExc_ValueError,
|
182
|
|
"Cannot set the NumPy array 'base' "
|
183
|
|
"dependency more than once");
|
184
|
0
|
return -1;
|
185
|
|
}
|
186
|
|
|
187
|
|
/*
|
188
|
|
* Don't allow infinite chains of views, always set the base
|
189
|
|
* to the first owner of the data.
|
190
|
|
* That is, either the first object which isn't an array,
|
191
|
|
* or the first object which owns its own data.
|
192
|
|
*/
|
193
|
|
|
194
|
1
|
while (PyArray_Check(obj) && (PyObject *)arr != obj) {
|
195
|
1
|
PyArrayObject *obj_arr = (PyArrayObject *)obj;
|
196
|
|
PyObject *tmp;
|
197
|
|
|
198
|
|
/* Propagate WARN_ON_WRITE through views. */
|
199
|
1
|
if (PyArray_FLAGS(obj_arr) & NPY_ARRAY_WARN_ON_WRITE) {
|
200
|
1
|
PyArray_ENABLEFLAGS(arr, NPY_ARRAY_WARN_ON_WRITE);
|
201
|
|
}
|
202
|
|
|
203
|
|
/* If this array owns its own data, stop collapsing */
|
204
|
1
|
if (PyArray_CHKFLAGS(obj_arr, NPY_ARRAY_OWNDATA)) {
|
205
|
|
break;
|
206
|
|
}
|
207
|
|
|
208
|
1
|
tmp = PyArray_BASE(obj_arr);
|
209
|
|
/* If there's no base, stop collapsing */
|
210
|
1
|
if (tmp == NULL) {
|
211
|
|
break;
|
212
|
|
}
|
213
|
|
/* Stop the collapse new base when the would not be of the same
|
214
|
|
* type (i.e. different subclass).
|
215
|
|
*/
|
216
|
1
|
if (Py_TYPE(tmp) != Py_TYPE(arr)) {
|
217
|
|
break;
|
218
|
|
}
|
219
|
|
|
220
|
|
|
221
|
1
|
Py_INCREF(tmp);
|
222
|
1
|
Py_DECREF(obj);
|
223
|
|
obj = tmp;
|
224
|
|
}
|
225
|
|
|
226
|
|
/* Disallow circular references */
|
227
|
1
|
if ((PyObject *)arr == obj) {
|
228
|
0
|
Py_DECREF(obj);
|
229
|
0
|
PyErr_SetString(PyExc_ValueError,
|
230
|
|
"Cannot create a circular NumPy array 'base' dependency");
|
231
|
0
|
return -1;
|
232
|
|
}
|
233
|
|
|
234
|
1
|
((PyArrayObject_fields *)arr)->base = obj;
|
235
|
|
|
236
|
1
|
return 0;
|
237
|
|
}
|
238
|
|
|
239
|
|
|
240
|
|
/**
|
241
|
|
* Assign an arbitrary object a NumPy array. This is largely basically
|
242
|
|
* identical to PyArray_FromAny, but assigns directly to the output array.
|
243
|
|
*
|
244
|
|
* @param dest Array to be written to
|
245
|
|
* @param src_object Object to be assigned, array-coercion rules apply.
|
246
|
|
* @return 0 on success -1 on failures.
|
247
|
|
*/
|
248
|
|
/*NUMPY_API*/
|
249
|
|
NPY_NO_EXPORT int
|
250
|
1
|
PyArray_CopyObject(PyArrayObject *dest, PyObject *src_object)
|
251
|
|
{
|
252
|
1
|
int ret = 0;
|
253
|
|
PyArrayObject *view;
|
254
|
1
|
PyArray_Descr *dtype = NULL;
|
255
|
|
int ndim;
|
256
|
|
npy_intp dims[NPY_MAXDIMS];
|
257
|
1
|
coercion_cache_obj *cache = NULL;
|
258
|
|
|
259
|
|
/*
|
260
|
|
* We have to set the maximum number of dimensions here to support
|
261
|
|
* sequences within object arrays.
|
262
|
|
*/
|
263
|
1
|
ndim = PyArray_DiscoverDTypeAndShape(src_object,
|
264
|
|
PyArray_NDIM(dest), dims, &cache,
|
265
|
1
|
NPY_DTYPE(PyArray_DESCR(dest)), PyArray_DESCR(dest), &dtype);
|
266
|
1
|
if (ndim < 0) {
|
267
|
|
return -1;
|
268
|
|
}
|
269
|
|
|
270
|
1
|
if (cache != NULL && !(cache->sequence)) {
|
271
|
|
/* The input is an array or array object, so assign directly */
|
272
|
|
assert(cache->converted_obj == src_object);
|
273
|
1
|
view = (PyArrayObject *)cache->arr_or_sequence;
|
274
|
1
|
Py_DECREF(dtype);
|
275
|
1
|
ret = PyArray_AssignArray(dest, view, NULL, NPY_UNSAFE_CASTING);
|
276
|
1
|
npy_free_coercion_cache(cache);
|
277
|
1
|
return ret;
|
278
|
|
}
|
279
|
|
|
280
|
|
/*
|
281
|
|
* We may need to broadcast, due to shape mismatches, in this case
|
282
|
|
* create a temporary array first, and assign that after filling
|
283
|
|
* it from the sequences/scalar.
|
284
|
|
*/
|
285
|
1
|
if (ndim != PyArray_NDIM(dest) ||
|
286
|
1
|
!PyArray_CompareLists(PyArray_DIMS(dest), dims, ndim)) {
|
287
|
|
/*
|
288
|
|
* Broadcasting may be necessary, so assign to a view first.
|
289
|
|
* This branch could lead to a shape mismatch error later.
|
290
|
|
*/
|
291
|
|
assert (ndim <= PyArray_NDIM(dest)); /* would error during discovery */
|
292
|
1
|
view = (PyArrayObject *) PyArray_NewFromDescr(
|
293
|
|
&PyArray_Type, dtype, ndim, dims, NULL, NULL,
|
294
|
1
|
PyArray_FLAGS(dest) & NPY_ARRAY_F_CONTIGUOUS, NULL);
|
295
|
1
|
if (view == NULL) {
|
296
|
0
|
npy_free_coercion_cache(cache);
|
297
|
0
|
return -1;
|
298
|
|
}
|
299
|
|
}
|
300
|
|
else {
|
301
|
1
|
Py_DECREF(dtype);
|
302
|
|
view = dest;
|
303
|
|
}
|
304
|
|
|
305
|
|
/* Assign the values to `view` (whichever array that is) */
|
306
|
1
|
if (cache == NULL) {
|
307
|
|
/* single (non-array) item, assign immediately */
|
308
|
1
|
if (PyArray_Pack(
|
309
|
1
|
PyArray_DESCR(view), PyArray_DATA(view), src_object) < 0) {
|
310
|
|
goto fail;
|
311
|
|
}
|
312
|
|
}
|
313
|
|
else {
|
314
|
1
|
if (PyArray_AssignFromCache(view, cache) < 0) {
|
315
|
|
goto fail;
|
316
|
|
}
|
317
|
|
}
|
318
|
1
|
if (view == dest) {
|
319
|
|
return 0;
|
320
|
|
}
|
321
|
1
|
ret = PyArray_AssignArray(dest, view, NULL, NPY_UNSAFE_CASTING);
|
322
|
1
|
Py_DECREF(view);
|
323
|
|
return ret;
|
324
|
|
|
325
|
0
|
fail:
|
326
|
0
|
if (view != dest) {
|
327
|
0
|
Py_DECREF(view);
|
328
|
|
}
|
329
|
|
return -1;
|
330
|
|
}
|
331
|
|
|
332
|
|
|
333
|
|
/* returns an Array-Scalar Object of the type of arr
|
334
|
|
from the given pointer to memory -- main Scalar creation function
|
335
|
|
default new method calls this.
|
336
|
|
*/
|
337
|
|
|
338
|
|
/* Ideally, here the descriptor would contain all the information needed.
|
339
|
|
So, that we simply need the data and the descriptor, and perhaps
|
340
|
|
a flag
|
341
|
|
*/
|
342
|
|
|
343
|
|
|
344
|
|
/*
|
345
|
|
Given a string return the type-number for
|
346
|
|
the data-type with that string as the type-object name.
|
347
|
|
Returns NPY_NOTYPE without setting an error if no type can be
|
348
|
|
found. Only works for user-defined data-types.
|
349
|
|
*/
|
350
|
|
|
351
|
|
/*NUMPY_API
|
352
|
|
*/
|
353
|
|
NPY_NO_EXPORT int
|
354
|
0
|
PyArray_TypeNumFromName(char const *str)
|
355
|
|
{
|
356
|
|
int i;
|
357
|
|
PyArray_Descr *descr;
|
358
|
|
|
359
|
0
|
for (i = 0; i < NPY_NUMUSERTYPES; i++) {
|
360
|
0
|
descr = userdescrs[i];
|
361
|
0
|
if (strcmp(descr->typeobj->tp_name, str) == 0) {
|
362
|
0
|
return descr->type_num;
|
363
|
|
}
|
364
|
|
}
|
365
|
|
return NPY_NOTYPE;
|
366
|
|
}
|
367
|
|
|
368
|
|
/*NUMPY_API
|
369
|
|
*
|
370
|
|
* If WRITEBACKIFCOPY and self has data, reset the base WRITEABLE flag,
|
371
|
|
* copy the local data to base, release the local data, and set flags
|
372
|
|
* appropriately. Return 0 if not relevant, 1 if success, < 0 on failure
|
373
|
|
*/
|
374
|
|
NPY_NO_EXPORT int
|
375
|
1
|
PyArray_ResolveWritebackIfCopy(PyArrayObject * self)
|
376
|
|
{
|
377
|
1
|
PyArrayObject_fields *fa = (PyArrayObject_fields *)self;
|
378
|
1
|
if (fa && fa->base) {
|
379
|
1
|
if ((fa->flags & NPY_ARRAY_UPDATEIFCOPY) || (fa->flags & NPY_ARRAY_WRITEBACKIFCOPY)) {
|
380
|
|
/*
|
381
|
|
* UPDATEIFCOPY or WRITEBACKIFCOPY means that fa->base's data
|
382
|
|
* should be updated with the contents
|
383
|
|
* of self.
|
384
|
|
* fa->base->flags is not WRITEABLE to protect the relationship
|
385
|
|
* unlock it.
|
386
|
|
*/
|
387
|
1
|
int retval = 0;
|
388
|
1
|
PyArray_ENABLEFLAGS(((PyArrayObject *)fa->base),
|
389
|
|
NPY_ARRAY_WRITEABLE);
|
390
|
1
|
PyArray_CLEARFLAGS(self, NPY_ARRAY_UPDATEIFCOPY);
|
391
|
1
|
PyArray_CLEARFLAGS(self, NPY_ARRAY_WRITEBACKIFCOPY);
|
392
|
1
|
retval = PyArray_CopyAnyInto((PyArrayObject *)fa->base, self);
|
393
|
1
|
Py_DECREF(fa->base);
|
394
|
1
|
fa->base = NULL;
|
395
|
1
|
if (retval < 0) {
|
396
|
|
/* this should never happen, how did the two copies of data
|
397
|
|
* get out of sync?
|
398
|
|
*/
|
399
|
|
return retval;
|
400
|
|
}
|
401
|
1
|
return 1;
|
402
|
|
}
|
403
|
|
}
|
404
|
|
return 0;
|
405
|
|
}
|
406
|
|
|
407
|
|
/*********************** end C-API functions **********************/
|
408
|
|
|
409
|
|
|
410
|
|
/* dealloc must not raise an error, best effort try to write
|
411
|
|
to stderr and clear the error
|
412
|
|
*/
|
413
|
|
|
414
|
|
static NPY_INLINE void
|
415
|
1
|
WARN_IN_DEALLOC(PyObject* warning, const char * msg) {
|
416
|
1
|
if (PyErr_WarnEx(warning, msg, 1) < 0) {
|
417
|
|
PyObject * s;
|
418
|
|
|
419
|
0
|
s = PyUnicode_FromString("array_dealloc");
|
420
|
0
|
if (s) {
|
421
|
0
|
PyErr_WriteUnraisable(s);
|
422
|
0
|
Py_DECREF(s);
|
423
|
|
}
|
424
|
|
else {
|
425
|
0
|
PyErr_WriteUnraisable(Py_None);
|
426
|
|
}
|
427
|
|
}
|
428
|
|
}
|
429
|
|
|
430
|
|
/* array object functions */
|
431
|
|
|
432
|
|
static void
|
433
|
1
|
array_dealloc(PyArrayObject *self)
|
434
|
|
{
|
435
|
1
|
PyArrayObject_fields *fa = (PyArrayObject_fields *)self;
|
436
|
|
|
437
|
1
|
_dealloc_cached_buffer_info((PyObject*)self);
|
438
|
|
|
439
|
1
|
if (fa->weakreflist != NULL) {
|
440
|
1
|
PyObject_ClearWeakRefs((PyObject *)self);
|
441
|
|
}
|
442
|
1
|
if (fa->base) {
|
443
|
|
int retval;
|
444
|
1
|
if (PyArray_FLAGS(self) & NPY_ARRAY_WRITEBACKIFCOPY)
|
445
|
|
{
|
446
|
1
|
char const * msg = "WRITEBACKIFCOPY detected in array_dealloc. "
|
447
|
|
" Required call to PyArray_ResolveWritebackIfCopy or "
|
448
|
|
"PyArray_DiscardWritebackIfCopy is missing.";
|
449
|
|
/*
|
450
|
|
* prevent reaching 0 twice and thus recursing into dealloc.
|
451
|
|
* Increasing sys.gettotalrefcount, but path should not be taken.
|
452
|
|
*/
|
453
|
1
|
Py_INCREF(self);
|
454
|
1
|
WARN_IN_DEALLOC(PyExc_RuntimeWarning, msg);
|
455
|
1
|
retval = PyArray_ResolveWritebackIfCopy(self);
|
456
|
1
|
if (retval < 0)
|
457
|
|
{
|
458
|
0
|
PyErr_Print();
|
459
|
0
|
PyErr_Clear();
|
460
|
|
}
|
461
|
|
}
|
462
|
1
|
if (PyArray_FLAGS(self) & NPY_ARRAY_UPDATEIFCOPY) {
|
463
|
|
/* DEPRECATED, remove once the flag is removed */
|
464
|
0
|
char const * msg = "UPDATEIFCOPY detected in array_dealloc. "
|
465
|
|
" Required call to PyArray_ResolveWritebackIfCopy or "
|
466
|
|
"PyArray_DiscardWritebackIfCopy is missing";
|
467
|
|
/*
|
468
|
|
* prevent reaching 0 twice and thus recursing into dealloc.
|
469
|
|
* Increasing sys.gettotalrefcount, but path should not be taken.
|
470
|
|
*/
|
471
|
0
|
Py_INCREF(self);
|
472
|
|
/* 2017-Nov-10 1.14 */
|
473
|
0
|
WARN_IN_DEALLOC(PyExc_DeprecationWarning, msg);
|
474
|
0
|
retval = PyArray_ResolveWritebackIfCopy(self);
|
475
|
0
|
if (retval < 0)
|
476
|
|
{
|
477
|
0
|
PyErr_Print();
|
478
|
0
|
PyErr_Clear();
|
479
|
|
}
|
480
|
|
}
|
481
|
|
/*
|
482
|
|
* If fa->base is non-NULL, it is something
|
483
|
|
* to DECREF -- either a view or a buffer object
|
484
|
|
*/
|
485
|
1
|
Py_XDECREF(fa->base);
|
486
|
|
}
|
487
|
|
|
488
|
1
|
if ((fa->flags & NPY_ARRAY_OWNDATA) && fa->data) {
|
489
|
|
/* Free internal references if an Object array */
|
490
|
1
|
if (PyDataType_FLAGCHK(fa->descr, NPY_ITEM_REFCOUNT)) {
|
491
|
1
|
PyArray_XDECREF(self);
|
492
|
|
}
|
493
|
1
|
npy_free_cache(fa->data, PyArray_NBYTES(self));
|
494
|
|
}
|
495
|
|
|
496
|
|
/* must match allocation in PyArray_NewFromDescr */
|
497
|
1
|
npy_free_cache_dim(fa->dimensions, 2 * fa->nd);
|
498
|
1
|
Py_DECREF(fa->descr);
|
499
|
1
|
Py_TYPE(self)->tp_free((PyObject *)self);
|
500
|
|
}
|
501
|
|
|
502
|
|
/*NUMPY_API
|
503
|
|
* Prints the raw data of the ndarray in a form useful for debugging
|
504
|
|
* low-level C issues.
|
505
|
|
*/
|
506
|
|
NPY_NO_EXPORT void
|
507
|
0
|
PyArray_DebugPrint(PyArrayObject *obj)
|
508
|
|
{
|
509
|
|
int i;
|
510
|
0
|
PyArrayObject_fields *fobj = (PyArrayObject_fields *)obj;
|
511
|
|
|
512
|
0
|
printf("-------------------------------------------------------\n");
|
513
|
0
|
printf(" Dump of NumPy ndarray at address %p\n", obj);
|
514
|
0
|
if (obj == NULL) {
|
515
|
0
|
printf(" It's NULL!\n");
|
516
|
0
|
printf("-------------------------------------------------------\n");
|
517
|
0
|
fflush(stdout);
|
518
|
0
|
return;
|
519
|
|
}
|
520
|
0
|
printf(" ndim : %d\n", fobj->nd);
|
521
|
0
|
printf(" shape :");
|
522
|
0
|
for (i = 0; i < fobj->nd; ++i) {
|
523
|
0
|
printf(" %" NPY_INTP_FMT, fobj->dimensions[i]);
|
524
|
|
}
|
525
|
0
|
printf("\n");
|
526
|
|
|
527
|
0
|
printf(" dtype : ");
|
528
|
0
|
PyObject_Print((PyObject *)fobj->descr, stdout, 0);
|
529
|
0
|
printf("\n");
|
530
|
0
|
printf(" data : %p\n", fobj->data);
|
531
|
0
|
printf(" strides:");
|
532
|
0
|
for (i = 0; i < fobj->nd; ++i) {
|
533
|
0
|
printf(" %" NPY_INTP_FMT, fobj->strides[i]);
|
534
|
|
}
|
535
|
0
|
printf("\n");
|
536
|
|
|
537
|
0
|
printf(" base : %p\n", fobj->base);
|
538
|
|
|
539
|
0
|
printf(" flags :");
|
540
|
0
|
if (fobj->flags & NPY_ARRAY_C_CONTIGUOUS)
|
541
|
|
printf(" NPY_C_CONTIGUOUS");
|
542
|
0
|
if (fobj->flags & NPY_ARRAY_F_CONTIGUOUS)
|
543
|
|
printf(" NPY_F_CONTIGUOUS");
|
544
|
0
|
if (fobj->flags & NPY_ARRAY_OWNDATA)
|
545
|
|
printf(" NPY_OWNDATA");
|
546
|
0
|
if (fobj->flags & NPY_ARRAY_ALIGNED)
|
547
|
|
printf(" NPY_ALIGNED");
|
548
|
0
|
if (fobj->flags & NPY_ARRAY_WRITEABLE)
|
549
|
|
printf(" NPY_WRITEABLE");
|
550
|
0
|
if (fobj->flags & NPY_ARRAY_UPDATEIFCOPY)
|
551
|
|
printf(" NPY_UPDATEIFCOPY");
|
552
|
0
|
if (fobj->flags & NPY_ARRAY_WRITEBACKIFCOPY)
|
553
|
|
printf(" NPY_WRITEBACKIFCOPY");
|
554
|
0
|
printf("\n");
|
555
|
|
|
556
|
0
|
if (fobj->base != NULL && PyArray_Check(fobj->base)) {
|
557
|
0
|
printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
|
558
|
0
|
printf("Dump of array's BASE:\n");
|
559
|
0
|
PyArray_DebugPrint((PyArrayObject *)fobj->base);
|
560
|
|
printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
|
561
|
|
}
|
562
|
0
|
printf("-------------------------------------------------------\n");
|
563
|
0
|
fflush(stdout);
|
564
|
|
}
|
565
|
|
|
566
|
|
|
567
|
|
/*NUMPY_API
|
568
|
|
* This function is scheduled to be removed
|
569
|
|
*
|
570
|
|
* TO BE REMOVED - NOT USED INTERNALLY.
|
571
|
|
*/
|
572
|
|
NPY_NO_EXPORT void
|
573
|
0
|
PyArray_SetDatetimeParseFunction(PyObject *NPY_UNUSED(op))
|
574
|
|
{
|
575
|
|
}
|
576
|
|
|
577
|
|
/*NUMPY_API
|
578
|
|
*/
|
579
|
|
NPY_NO_EXPORT int
|
580
|
0
|
PyArray_CompareUCS4(npy_ucs4 const *s1, npy_ucs4 const *s2, size_t len)
|
581
|
|
{
|
582
|
|
npy_ucs4 c1, c2;
|
583
|
1
|
while(len-- > 0) {
|
584
|
1
|
c1 = *s1++;
|
585
|
1
|
c2 = *s2++;
|
586
|
1
|
if (c1 != c2) {
|
587
|
1
|
return (c1 < c2) ? -1 : 1;
|
588
|
|
}
|
589
|
|
}
|
590
|
|
return 0;
|
591
|
|
}
|
592
|
|
|
593
|
|
/*NUMPY_API
|
594
|
|
*/
|
595
|
|
NPY_NO_EXPORT int
|
596
|
0
|
PyArray_CompareString(const char *s1, const char *s2, size_t len)
|
597
|
|
{
|
598
|
0
|
const unsigned char *c1 = (unsigned char *)s1;
|
599
|
0
|
const unsigned char *c2 = (unsigned char *)s2;
|
600
|
|
size_t i;
|
601
|
|
|
602
|
0
|
for(i = 0; i < len; ++i) {
|
603
|
0
|
if (c1[i] != c2[i]) {
|
604
|
0
|
return (c1[i] > c2[i]) ? 1 : -1;
|
605
|
|
}
|
606
|
|
}
|
607
|
|
return 0;
|
608
|
|
}
|
609
|
|
|
610
|
|
|
611
|
|
/* Call this from contexts where an array might be written to, but we have no
|
612
|
|
* way to tell. (E.g., when converting to a read-write buffer.)
|
613
|
|
*/
|
614
|
|
NPY_NO_EXPORT int
|
615
|
1
|
array_might_be_written(PyArrayObject *obj)
|
616
|
|
{
|
617
|
1
|
const char *msg =
|
618
|
|
"Numpy has detected that you (may be) writing to an array with\n"
|
619
|
|
"overlapping memory from np.broadcast_arrays. If this is intentional\n"
|
620
|
|
"set the WRITEABLE flag True or make a copy immediately before writing.";
|
621
|
1
|
if (PyArray_FLAGS(obj) & NPY_ARRAY_WARN_ON_WRITE) {
|
622
|
1
|
if (DEPRECATE(msg) < 0) {
|
623
|
|
return -1;
|
624
|
|
}
|
625
|
|
/* Only warn once per array */
|
626
|
|
while (1) {
|
627
|
1
|
PyArray_CLEARFLAGS(obj, NPY_ARRAY_WARN_ON_WRITE);
|
628
|
1
|
if (!PyArray_BASE(obj) || !PyArray_Check(PyArray_BASE(obj))) {
|
629
|
|
break;
|
630
|
|
}
|
631
|
1
|
obj = (PyArrayObject *)PyArray_BASE(obj);
|
632
|
|
}
|
633
|
|
}
|
634
|
|
return 0;
|
635
|
|
}
|
636
|
|
|
637
|
|
/*NUMPY_API
|
638
|
|
*
|
639
|
|
* This function does nothing if obj is writeable, and raises an exception
|
640
|
|
* (and returns -1) if obj is not writeable. It may also do other
|
641
|
|
* house-keeping, such as issuing warnings on arrays which are transitioning
|
642
|
|
* to become views. Always call this function at some point before writing to
|
643
|
|
* an array.
|
644
|
|
*
|
645
|
|
* 'name' is a name for the array, used to give better error
|
646
|
|
* messages. Something like "assignment destination", "output array", or even
|
647
|
|
* just "array".
|
648
|
|
*/
|
649
|
|
NPY_NO_EXPORT int
|
650
|
1
|
PyArray_FailUnlessWriteable(PyArrayObject *obj, const char *name)
|
651
|
|
{
|
652
|
1
|
if (!PyArray_ISWRITEABLE(obj)) {
|
653
|
1
|
PyErr_Format(PyExc_ValueError, "%s is read-only", name);
|
654
|
1
|
return -1;
|
655
|
|
}
|
656
|
1
|
if (array_might_be_written(obj) < 0) {
|
657
|
|
return -1;
|
658
|
|
}
|
659
|
1
|
return 0;
|
660
|
|
}
|
661
|
|
|
662
|
|
/* This also handles possibly mis-aligned data */
|
663
|
|
/* Compare s1 and s2 which are not necessarily NULL-terminated.
|
664
|
|
s1 is of length len1
|
665
|
|
s2 is of length len2
|
666
|
|
If they are NULL terminated, then stop comparison.
|
667
|
|
*/
|
668
|
|
static int
|
669
|
1
|
_myunincmp(npy_ucs4 const *s1, npy_ucs4 const *s2, int len1, int len2)
|
670
|
|
{
|
671
|
|
npy_ucs4 const *sptr;
|
672
|
1
|
npy_ucs4 *s1t = NULL;
|
673
|
1
|
npy_ucs4 *s2t = NULL;
|
674
|
|
int val;
|
675
|
|
npy_intp size;
|
676
|
|
int diff;
|
677
|
|
|
678
|
|
/* Replace `s1` and `s2` with aligned copies if needed */
|
679
|
1
|
if ((npy_intp)s1 % sizeof(npy_ucs4) != 0) {
|
680
|
1
|
size = len1*sizeof(npy_ucs4);
|
681
|
1
|
s1t = malloc(size);
|
682
|
1
|
memcpy(s1t, s1, size);
|
683
|
1
|
s1 = s1t;
|
684
|
|
}
|
685
|
1
|
if ((npy_intp)s2 % sizeof(npy_ucs4) != 0) {
|
686
|
0
|
size = len2*sizeof(npy_ucs4);
|
687
|
0
|
s2t = malloc(size);
|
688
|
0
|
memcpy(s2t, s2, size);
|
689
|
0
|
s2 = s1t;
|
690
|
|
}
|
691
|
|
|
692
|
1
|
val = PyArray_CompareUCS4(s1, s2, PyArray_MIN(len1,len2));
|
693
|
1
|
if ((val != 0) || (len1 == len2)) {
|
694
|
|
goto finish;
|
695
|
|
}
|
696
|
1
|
if (len2 > len1) {
|
697
|
1
|
sptr = s2+len1;
|
698
|
1
|
val = -1;
|
699
|
1
|
diff = len2-len1;
|
700
|
|
}
|
701
|
|
else {
|
702
|
1
|
sptr = s1+len2;
|
703
|
1
|
val = 1;
|
704
|
1
|
diff=len1-len2;
|
705
|
|
}
|
706
|
1
|
while (diff--) {
|
707
|
1
|
if (*sptr != 0) {
|
708
|
|
goto finish;
|
709
|
|
}
|
710
|
1
|
sptr++;
|
711
|
|
}
|
712
|
|
val = 0;
|
713
|
|
|
714
|
1
|
finish:
|
715
|
|
/* Cleanup the aligned copies */
|
716
|
1
|
if (s1t) {
|
717
|
1
|
free(s1t);
|
718
|
|
}
|
719
|
1
|
if (s2t) {
|
720
|
0
|
free(s2t);
|
721
|
|
}
|
722
|
1
|
return val;
|
723
|
|
}
|
724
|
|
|
725
|
|
|
726
|
|
|
727
|
|
|
728
|
|
/*
|
729
|
|
* Compare s1 and s2 which are not necessarily NULL-terminated.
|
730
|
|
* s1 is of length len1
|
731
|
|
* s2 is of length len2
|
732
|
|
* If they are NULL terminated, then stop comparison.
|
733
|
|
*/
|
734
|
|
static int
|
735
|
1
|
_mystrncmp(char const *s1, char const *s2, int len1, int len2)
|
736
|
|
{
|
737
|
|
char const *sptr;
|
738
|
|
int val;
|
739
|
|
int diff;
|
740
|
|
|
741
|
1
|
val = memcmp(s1, s2, PyArray_MIN(len1, len2));
|
742
|
1
|
if ((val != 0) || (len1 == len2)) {
|
743
|
|
return val;
|
744
|
|
}
|
745
|
1
|
if (len2 > len1) {
|
746
|
1
|
sptr = s2 + len1;
|
747
|
1
|
val = -1;
|
748
|
1
|
diff = len2 - len1;
|
749
|
|
}
|
750
|
|
else {
|
751
|
1
|
sptr = s1 + len2;
|
752
|
1
|
val = 1;
|
753
|
1
|
diff = len1 - len2;
|
754
|
|
}
|
755
|
1
|
while (diff--) {
|
756
|
1
|
if (*sptr != 0) {
|
757
|
|
return val;
|
758
|
|
}
|
759
|
1
|
sptr++;
|
760
|
|
}
|
761
|
|
return 0; /* Only happens if NULLs are everywhere */
|
762
|
|
}
|
763
|
|
|
764
|
|
/* Borrowed from Numarray */
|
765
|
|
|
766
|
|
#define SMALL_STRING 2048
|
767
|
|
|
768
|
1
|
static void _rstripw(char *s, int n)
|
769
|
|
{
|
770
|
|
int i;
|
771
|
1
|
for (i = n - 1; i >= 1; i--) { /* Never strip to length 0. */
|
772
|
1
|
int c = s[i];
|
773
|
|
|
774
|
1
|
if (!c || NumPyOS_ascii_isspace((int)c)) {
|
775
|
1
|
s[i] = 0;
|
776
|
|
}
|
777
|
|
else {
|
778
|
|
break;
|
779
|
|
}
|
780
|
|
}
|
781
|
|
}
|
782
|
|
|
783
|
1
|
static void _unistripw(npy_ucs4 *s, int n)
|
784
|
|
{
|
785
|
|
int i;
|
786
|
1
|
for (i = n - 1; i >= 1; i--) { /* Never strip to length 0. */
|
787
|
1
|
npy_ucs4 c = s[i];
|
788
|
1
|
if (!c || NumPyOS_ascii_isspace((int)c)) {
|
789
|
1
|
s[i] = 0;
|
790
|
|
}
|
791
|
|
else {
|
792
|
|
break;
|
793
|
|
}
|
794
|
|
}
|
795
|
|
}
|
796
|
|
|
797
|
|
|
798
|
|
static char *
|
799
|
1
|
_char_copy_n_strip(char const *original, char *temp, int nc)
|
800
|
|
{
|
801
|
1
|
if (nc > SMALL_STRING) {
|
802
|
0
|
temp = malloc(nc);
|
803
|
0
|
if (!temp) {
|
804
|
0
|
PyErr_NoMemory();
|
805
|
0
|
return NULL;
|
806
|
|
}
|
807
|
|
}
|
808
|
1
|
memcpy(temp, original, nc);
|
809
|
1
|
_rstripw(temp, nc);
|
810
|
1
|
return temp;
|
811
|
|
}
|
812
|
|
|
813
|
|
static void
|
814
|
1
|
_char_release(char *ptr, int nc)
|
815
|
|
{
|
816
|
1
|
if (nc > SMALL_STRING) {
|
817
|
0
|
free(ptr);
|
818
|
|
}
|
819
|
|
}
|
820
|
|
|
821
|
|
static char *
|
822
|
1
|
_uni_copy_n_strip(char const *original, char *temp, int nc)
|
823
|
|
{
|
824
|
1
|
if (nc*sizeof(npy_ucs4) > SMALL_STRING) {
|
825
|
1
|
temp = malloc(nc*sizeof(npy_ucs4));
|
826
|
1
|
if (!temp) {
|
827
|
0
|
PyErr_NoMemory();
|
828
|
0
|
return NULL;
|
829
|
|
}
|
830
|
|
}
|
831
|
1
|
memcpy(temp, original, nc*sizeof(npy_ucs4));
|
832
|
1
|
_unistripw((npy_ucs4 *)temp, nc);
|
833
|
1
|
return temp;
|
834
|
|
}
|
835
|
|
|
836
|
|
static void
|
837
|
1
|
_uni_release(char *ptr, int nc)
|
838
|
|
{
|
839
|
1
|
if (nc*sizeof(npy_ucs4) > SMALL_STRING) {
|
840
|
1
|
free(ptr);
|
841
|
|
}
|
842
|
|
}
|
843
|
|
|
844
|
|
|
845
|
|
/* End borrowed from numarray */
|
846
|
|
|
847
|
|
#define _rstrip_loop(CMP) { \
|
848
|
|
void *aptr, *bptr; \
|
849
|
|
char atemp[SMALL_STRING], btemp[SMALL_STRING]; \
|
850
|
|
while(size--) { \
|
851
|
|
aptr = stripfunc(iself->dataptr, atemp, N1); \
|
852
|
|
if (!aptr) return -1; \
|
853
|
|
bptr = stripfunc(iother->dataptr, btemp, N2); \
|
854
|
|
if (!bptr) { \
|
855
|
|
relfunc(aptr, N1); \
|
856
|
|
return -1; \
|
857
|
|
} \
|
858
|
|
val = compfunc(aptr, bptr, N1, N2); \
|
859
|
|
*dptr = (val CMP 0); \
|
860
|
|
PyArray_ITER_NEXT(iself); \
|
861
|
|
PyArray_ITER_NEXT(iother); \
|
862
|
|
dptr += 1; \
|
863
|
|
relfunc(aptr, N1); \
|
864
|
|
relfunc(bptr, N2); \
|
865
|
|
} \
|
866
|
|
}
|
867
|
|
|
868
|
|
#define _reg_loop(CMP) { \
|
869
|
|
while(size--) { \
|
870
|
|
val = compfunc((void *)iself->dataptr, \
|
871
|
|
(void *)iother->dataptr, \
|
872
|
|
N1, N2); \
|
873
|
|
*dptr = (val CMP 0); \
|
874
|
|
PyArray_ITER_NEXT(iself); \
|
875
|
|
PyArray_ITER_NEXT(iother); \
|
876
|
|
dptr += 1; \
|
877
|
|
} \
|
878
|
|
}
|
879
|
|
|
880
|
|
static int
|
881
|
1
|
_compare_strings(PyArrayObject *result, PyArrayMultiIterObject *multi,
|
882
|
|
int cmp_op, void *func, int rstrip)
|
883
|
|
{
|
884
|
|
PyArrayIterObject *iself, *iother;
|
885
|
|
npy_bool *dptr;
|
886
|
|
npy_intp size;
|
887
|
|
int val;
|
888
|
|
int N1, N2;
|
889
|
|
int (*compfunc)(void *, void *, int, int);
|
890
|
|
void (*relfunc)(char *, int);
|
891
|
|
char* (*stripfunc)(char const *, char *, int);
|
892
|
|
|
893
|
1
|
compfunc = func;
|
894
|
1
|
dptr = (npy_bool *)PyArray_DATA(result);
|
895
|
1
|
iself = multi->iters[0];
|
896
|
1
|
iother = multi->iters[1];
|
897
|
1
|
size = multi->size;
|
898
|
1
|
N1 = PyArray_DESCR(iself->ao)->elsize;
|
899
|
1
|
N2 = PyArray_DESCR(iother->ao)->elsize;
|
900
|
1
|
if ((void *)compfunc == (void *)_myunincmp) {
|
901
|
1
|
N1 >>= 2;
|
902
|
1
|
N2 >>= 2;
|
903
|
1
|
stripfunc = _uni_copy_n_strip;
|
904
|
1
|
relfunc = _uni_release;
|
905
|
|
}
|
906
|
|
else {
|
907
|
|
stripfunc = _char_copy_n_strip;
|
908
|
|
relfunc = _char_release;
|
909
|
|
}
|
910
|
1
|
switch (cmp_op) {
|
911
|
1
|
case Py_EQ:
|
912
|
1
|
if (rstrip) {
|
913
|
1
|
_rstrip_loop(==);
|
914
|
|
} else {
|
915
|
1
|
_reg_loop(==);
|
916
|
|
}
|
917
|
|
break;
|
918
|
1
|
case Py_NE:
|
919
|
1
|
if (rstrip) {
|
920
|
1
|
_rstrip_loop(!=);
|
921
|
|
} else {
|
922
|
1
|
_reg_loop(!=);
|
923
|
|
}
|
924
|
|
break;
|
925
|
1
|
case Py_LT:
|
926
|
1
|
if (rstrip) {
|
927
|
1
|
_rstrip_loop(<);
|
928
|
|
} else {
|
929
|
1
|
_reg_loop(<);
|
930
|
|
}
|
931
|
|
break;
|
932
|
1
|
case Py_LE:
|
933
|
1
|
if (rstrip) {
|
934
|
1
|
_rstrip_loop(<=);
|
935
|
|
} else {
|
936
|
1
|
_reg_loop(<=);
|
937
|
|
}
|
938
|
|
break;
|
939
|
1
|
case Py_GT:
|
940
|
1
|
if (rstrip) {
|
941
|
1
|
_rstrip_loop(>);
|
942
|
|
} else {
|
943
|
1
|
_reg_loop(>);
|
944
|
|
}
|
945
|
|
break;
|
946
|
1
|
case Py_GE:
|
947
|
1
|
if (rstrip) {
|
948
|
1
|
_rstrip_loop(>=);
|
949
|
|
} else {
|
950
|
1
|
_reg_loop(>=);
|
951
|
|
}
|
952
|
|
break;
|
953
|
0
|
default:
|
954
|
0
|
PyErr_SetString(PyExc_RuntimeError, "bad comparison operator");
|
955
|
0
|
return -1;
|
956
|
|
}
|
957
|
|
return 0;
|
958
|
|
}
|
959
|
|
|
960
|
|
#undef _reg_loop
|
961
|
|
#undef _rstrip_loop
|
962
|
|
#undef SMALL_STRING
|
963
|
|
|
964
|
|
NPY_NO_EXPORT PyObject *
|
965
|
1
|
_strings_richcompare(PyArrayObject *self, PyArrayObject *other, int cmp_op,
|
966
|
|
int rstrip)
|
967
|
|
{
|
968
|
|
PyArrayObject *result;
|
969
|
|
PyArrayMultiIterObject *mit;
|
970
|
|
int val;
|
971
|
|
|
972
|
|
/* Cast arrays to a common type */
|
973
|
1
|
if (PyArray_TYPE(self) != PyArray_DESCR(other)->type_num) {
|
974
|
|
/*
|
975
|
|
* Comparison between Bytes and Unicode is not defined in Py3K;
|
976
|
|
* we follow.
|
977
|
|
*/
|
978
|
1
|
Py_INCREF(Py_NotImplemented);
|
979
|
1
|
return Py_NotImplemented;
|
980
|
|
}
|
981
|
1
|
if (PyArray_ISNOTSWAPPED(self) != PyArray_ISNOTSWAPPED(other)) {
|
982
|
|
PyObject *new;
|
983
|
1
|
if (PyArray_TYPE(self) == NPY_STRING &&
|
984
|
|
PyArray_DESCR(other)->type_num == NPY_UNICODE) {
|
985
|
|
PyArray_Descr* unicode = PyArray_DescrNew(PyArray_DESCR(other));
|
986
|
|
unicode->elsize = PyArray_DESCR(self)->elsize << 2;
|
987
|
|
new = PyArray_FromAny((PyObject *)self, unicode,
|
988
|
|
0, 0, 0, NULL);
|
989
|
|
if (new == NULL) {
|
990
|
|
return NULL;
|
991
|
|
}
|
992
|
|
Py_INCREF(other);
|
993
|
|
self = (PyArrayObject *)new;
|
994
|
|
}
|
995
|
1
|
else if ((PyArray_TYPE(self) == NPY_UNICODE) &&
|
996
|
1
|
((PyArray_DESCR(other)->type_num == NPY_STRING) ||
|
997
|
1
|
(PyArray_ISNOTSWAPPED(self) != PyArray_ISNOTSWAPPED(other)))) {
|
998
|
1
|
PyArray_Descr* unicode = PyArray_DescrNew(PyArray_DESCR(self));
|
999
|
|
|
1000
|
1
|
if (PyArray_DESCR(other)->type_num == NPY_STRING) {
|
1001
|
0
|
unicode->elsize = PyArray_DESCR(other)->elsize << 2;
|
1002
|
|
}
|
1003
|
|
else {
|
1004
|
1
|
unicode->elsize = PyArray_DESCR(other)->elsize;
|
1005
|
|
}
|
1006
|
1
|
new = PyArray_FromAny((PyObject *)other, unicode,
|
1007
|
|
0, 0, 0, NULL);
|
1008
|
1
|
if (new == NULL) {
|
1009
|
|
return NULL;
|
1010
|
|
}
|
1011
|
1
|
Py_INCREF(self);
|
1012
|
1
|
other = (PyArrayObject *)new;
|
1013
|
|
}
|
1014
|
|
else {
|
1015
|
0
|
PyErr_SetString(PyExc_TypeError,
|
1016
|
|
"invalid string data-types "
|
1017
|
|
"in comparison");
|
1018
|
0
|
return NULL;
|
1019
|
|
}
|
1020
|
|
}
|
1021
|
|
else {
|
1022
|
1
|
Py_INCREF(self);
|
1023
|
1
|
Py_INCREF(other);
|
1024
|
|
}
|
1025
|
|
|
1026
|
|
/* Broad-cast the arrays to a common shape */
|
1027
|
1
|
mit = (PyArrayMultiIterObject *)PyArray_MultiIterNew(2, self, other);
|
1028
|
1
|
Py_DECREF(self);
|
1029
|
1
|
Py_DECREF(other);
|
1030
|
1
|
if (mit == NULL) {
|
1031
|
|
return NULL;
|
1032
|
|
}
|
1033
|
|
|
1034
|
1
|
result = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type,
|
1035
|
|
PyArray_DescrFromType(NPY_BOOL),
|
1036
|
|
mit->nd,
|
1037
|
1
|
mit->dimensions,
|
1038
|
|
NULL, NULL, 0,
|
1039
|
|
NULL);
|
1040
|
1
|
if (result == NULL) {
|
1041
|
|
goto finish;
|
1042
|
|
}
|
1043
|
|
|
1044
|
1
|
if (PyArray_TYPE(self) == NPY_UNICODE) {
|
1045
|
1
|
val = _compare_strings(result, mit, cmp_op, _myunincmp, rstrip);
|
1046
|
|
}
|
1047
|
|
else {
|
1048
|
1
|
val = _compare_strings(result, mit, cmp_op, _mystrncmp, rstrip);
|
1049
|
|
}
|
1050
|
|
|
1051
|
1
|
if (val < 0) {
|
1052
|
0
|
Py_DECREF(result);
|
1053
|
|
result = NULL;
|
1054
|
|
}
|
1055
|
|
|
1056
|
1
|
finish:
|
1057
|
1
|
Py_DECREF(mit);
|
1058
|
|
return (PyObject *)result;
|
1059
|
|
}
|
1060
|
|
|
1061
|
|
/*
|
1062
|
|
* VOID-type arrays can only be compared equal and not-equal
|
1063
|
|
* in which case the fields are all compared by extracting the fields
|
1064
|
|
* and testing one at a time...
|
1065
|
|
* equality testing is performed using logical_ands on all the fields.
|
1066
|
|
* in-equality testing is performed using logical_ors on all the fields.
|
1067
|
|
*
|
1068
|
|
* VOID-type arrays without fields are compared for equality by comparing their
|
1069
|
|
* memory at each location directly (using string-code).
|
1070
|
|
*/
|
1071
|
|
static PyObject *
|
1072
|
1
|
_void_compare(PyArrayObject *self, PyArrayObject *other, int cmp_op)
|
1073
|
|
{
|
1074
|
1
|
if (!(cmp_op == Py_EQ || cmp_op == Py_NE)) {
|
1075
|
0
|
PyErr_SetString(PyExc_ValueError,
|
1076
|
|
"Void-arrays can only be compared for equality.");
|
1077
|
0
|
return NULL;
|
1078
|
|
}
|
1079
|
1
|
if (PyArray_HASFIELDS(self)) {
|
1080
|
1
|
PyObject *res = NULL, *temp, *a, *b;
|
1081
|
|
PyObject *key, *value, *temp2;
|
1082
|
|
PyObject *op;
|
1083
|
1
|
Py_ssize_t pos = 0;
|
1084
|
1
|
npy_intp result_ndim = PyArray_NDIM(self) > PyArray_NDIM(other) ?
|
1085
|
1
|
PyArray_NDIM(self) : PyArray_NDIM(other);
|
1086
|
|
|
1087
|
1
|
op = (cmp_op == Py_EQ ? n_ops.logical_and : n_ops.logical_or);
|
1088
|
1
|
while (PyDict_Next(PyArray_DESCR(self)->fields, &pos, &key, &value)) {
|
1089
|
1
|
if (NPY_TITLE_KEY(key, value)) {
|
1090
|
1
|
continue;
|
1091
|
|
}
|
1092
|
1
|
a = array_subscript_asarray(self, key);
|
1093
|
1
|
if (a == NULL) {
|
1094
|
0
|
Py_XDECREF(res);
|
1095
|
|
return NULL;
|
1096
|
|
}
|
1097
|
1
|
b = array_subscript_asarray(other, key);
|
1098
|
1
|
if (b == NULL) {
|
1099
|
0
|
Py_XDECREF(res);
|
1100
|
0
|
Py_DECREF(a);
|
1101
|
|
return NULL;
|
1102
|
|
}
|
1103
|
1
|
temp = array_richcompare((PyArrayObject *)a,b,cmp_op);
|
1104
|
1
|
Py_DECREF(a);
|
1105
|
1
|
Py_DECREF(b);
|
1106
|
1
|
if (temp == NULL) {
|
1107
|
1
|
Py_XDECREF(res);
|
1108
|
|
return NULL;
|
1109
|
|
}
|
1110
|
|
|
1111
|
|
/*
|
1112
|
|
* If the field type has a non-trivial shape, additional
|
1113
|
|
* dimensions will have been appended to `a` and `b`.
|
1114
|
|
* In that case, reduce them using `op`.
|
1115
|
|
*/
|
1116
|
1
|
if (PyArray_Check(temp) &&
|
1117
|
1
|
PyArray_NDIM((PyArrayObject *)temp) > result_ndim) {
|
1118
|
|
/* If the type was multidimensional, collapse that part to 1-D
|
1119
|
|
*/
|
1120
|
1
|
if (PyArray_NDIM((PyArrayObject *)temp) != result_ndim+1) {
|
1121
|
|
npy_intp dimensions[NPY_MAXDIMS];
|
1122
|
|
PyArray_Dims newdims;
|
1123
|
|
|
1124
|
1
|
newdims.ptr = dimensions;
|
1125
|
1
|
newdims.len = result_ndim+1;
|
1126
|
1
|
if (result_ndim) {
|
1127
|
1
|
memcpy(dimensions, PyArray_DIMS((PyArrayObject *)temp),
|
1128
|
|
sizeof(npy_intp)*result_ndim);
|
1129
|
|
}
|
1130
|
1
|
dimensions[result_ndim] = -1;
|
1131
|
1
|
temp2 = PyArray_Newshape((PyArrayObject *)temp,
|
1132
|
|
&newdims, NPY_ANYORDER);
|
1133
|
1
|
if (temp2 == NULL) {
|
1134
|
0
|
Py_DECREF(temp);
|
1135
|
0
|
Py_XDECREF(res);
|
1136
|
0
|
return NULL;
|
1137
|
|
}
|
1138
|
1
|
Py_DECREF(temp);
|
1139
|
1
|
temp = temp2;
|
1140
|
|
}
|
1141
|
|
/* Reduce the extra dimension of `temp` using `op` */
|
1142
|
1
|
temp2 = PyArray_GenericReduceFunction((PyArrayObject *)temp,
|
1143
|
|
op, result_ndim,
|
1144
|
|
NPY_BOOL, NULL);
|
1145
|
1
|
if (temp2 == NULL) {
|
1146
|
0
|
Py_DECREF(temp);
|
1147
|
0
|
Py_XDECREF(res);
|
1148
|
|
return NULL;
|
1149
|
|
}
|
1150
|
1
|
Py_DECREF(temp);
|
1151
|
|
temp = temp2;
|
1152
|
|
}
|
1153
|
|
|
1154
|
1
|
if (res == NULL) {
|
1155
|
|
res = temp;
|
1156
|
|
}
|
1157
|
|
else {
|
1158
|
1
|
temp2 = PyObject_CallFunction(op, "OO", res, temp);
|
1159
|
1
|
Py_DECREF(temp);
|
1160
|
1
|
Py_DECREF(res);
|
1161
|
1
|
if (temp2 == NULL) {
|
1162
|
|
return NULL;
|
1163
|
|
}
|
1164
|
|
res = temp2;
|
1165
|
|
}
|
1166
|
|
}
|
1167
|
1
|
if (res == NULL && !PyErr_Occurred()) {
|
1168
|
|
/* these dtypes had no fields. Use a MultiIter to broadcast them
|
1169
|
|
* to an output array, and fill with True (for EQ)*/
|
1170
|
1
|
PyArrayMultiIterObject *mit = (PyArrayMultiIterObject *)
|
1171
|
|
PyArray_MultiIterNew(2, self, other);
|
1172
|
1
|
if (mit == NULL) {
|
1173
|
|
return NULL;
|
1174
|
|
}
|
1175
|
|
|
1176
|
1
|
res = PyArray_NewFromDescr(&PyArray_Type,
|
1177
|
|
PyArray_DescrFromType(NPY_BOOL),
|
1178
|
1
|
mit->nd, mit->dimensions,
|
1179
|
|
NULL, NULL, 0, NULL);
|
1180
|
1
|
Py_DECREF(mit);
|
1181
|
1
|
if (res) {
|
1182
|
1
|
PyArray_FILLWBYTE((PyArrayObject *)res,
|
1183
|
|
cmp_op == Py_EQ ? 1 : 0);
|
1184
|
|
}
|
1185
|
|
}
|
1186
|
|
return res;
|
1187
|
|
}
|
1188
|
|
else {
|
1189
|
|
/* compare as a string. Assumes self and other have same descr->type */
|
1190
|
1
|
return _strings_richcompare(self, other, cmp_op, 0);
|
1191
|
|
}
|
1192
|
|
}
|
1193
|
|
|
1194
|
|
/*
|
1195
|
|
* Silence the current error and emit a deprecation warning instead.
|
1196
|
|
*
|
1197
|
|
* If warnings are raised as errors, this sets the warning __cause__ to the
|
1198
|
|
* silenced error.
|
1199
|
|
*/
|
1200
|
|
NPY_NO_EXPORT int
|
1201
|
0
|
DEPRECATE_silence_error(const char *msg) {
|
1202
|
|
PyObject *exc, *val, *tb;
|
1203
|
0
|
PyErr_Fetch(&exc, &val, &tb);
|
1204
|
0
|
if (DEPRECATE(msg) < 0) {
|
1205
|
0
|
npy_PyErr_ChainExceptionsCause(exc, val, tb);
|
1206
|
0
|
return -1;
|
1207
|
|
}
|
1208
|
0
|
Py_XDECREF(exc);
|
1209
|
0
|
Py_XDECREF(val);
|
1210
|
0
|
Py_XDECREF(tb);
|
1211
|
|
return 0;
|
1212
|
|
}
|
1213
|
|
|
1214
|
|
/*
|
1215
|
|
* Comparisons can fail, but we do not always want to pass on the exception
|
1216
|
|
* (see comment in array_richcompare below), but rather return NotImplemented.
|
1217
|
|
* Here, an exception should be set on entrance.
|
1218
|
|
* Returns either NotImplemented with the exception cleared, or NULL
|
1219
|
|
* with the exception set.
|
1220
|
|
* Raises deprecation warnings for cases where behaviour is meant to change
|
1221
|
|
* (2015-05-14, 1.10)
|
1222
|
|
*/
|
1223
|
|
|
1224
|
|
NPY_NO_EXPORT PyObject *
|
1225
|
1
|
_failed_comparison_workaround(PyArrayObject *self, PyObject *other, int cmp_op)
|
1226
|
|
{
|
1227
|
|
PyObject *exc, *val, *tb;
|
1228
|
|
PyArrayObject *array_other;
|
1229
|
|
int other_is_flexible, ndim_other;
|
1230
|
1
|
int self_is_flexible = PyTypeNum_ISFLEXIBLE(PyArray_DESCR(self)->type_num);
|
1231
|
|
|
1232
|
1
|
PyErr_Fetch(&exc, &val, &tb);
|
1233
|
|
/*
|
1234
|
|
* Determine whether other has a flexible dtype; here, inconvertible
|
1235
|
|
* is counted as inflexible. (This repeats work done in the ufunc,
|
1236
|
|
* but OK to waste some time in an unlikely path.)
|
1237
|
|
*/
|
1238
|
1
|
array_other = (PyArrayObject *)PyArray_FROM_O(other);
|
1239
|
1
|
if (array_other) {
|
1240
|
1
|
other_is_flexible = PyTypeNum_ISFLEXIBLE(
|
1241
|
|
PyArray_DESCR(array_other)->type_num);
|
1242
|
1
|
ndim_other = PyArray_NDIM(array_other);
|
1243
|
1
|
Py_DECREF(array_other);
|
1244
|
|
}
|
1245
|
|
else {
|
1246
|
1
|
PyErr_Clear(); /* we restore the original error if needed */
|
1247
|
1
|
other_is_flexible = 0;
|
1248
|
1
|
ndim_other = 0;
|
1249
|
|
}
|
1250
|
1
|
if (cmp_op == Py_EQ || cmp_op == Py_NE) {
|
1251
|
|
/*
|
1252
|
|
* note: for == and !=, a structured dtype self cannot get here,
|
1253
|
|
* but a string can. Other can be string or structured.
|
1254
|
|
*/
|
1255
|
1
|
if (other_is_flexible || self_is_flexible) {
|
1256
|
|
/*
|
1257
|
|
* For scalars, returning NotImplemented is correct.
|
1258
|
|
* For arrays, we emit a future deprecation warning.
|
1259
|
|
* When this warning is removed, a correctly shaped
|
1260
|
|
* array of bool should be returned.
|
1261
|
|
*/
|
1262
|
1
|
if (ndim_other != 0 || PyArray_NDIM(self) != 0) {
|
1263
|
|
/* 2015-05-14, 1.10 */
|
1264
|
1
|
if (DEPRECATE_FUTUREWARNING(
|
1265
|
|
"elementwise comparison failed; returning scalar "
|
1266
|
|
"instead, but in the future will perform "
|
1267
|
|
"elementwise comparison") < 0) {
|
1268
|
|
goto fail;
|
1269
|
|
}
|
1270
|
|
}
|
1271
|
|
}
|
1272
|
|
else {
|
1273
|
|
/*
|
1274
|
|
* If neither self nor other had a flexible dtype, the error cannot
|
1275
|
|
* have been caused by a lack of implementation in the ufunc.
|
1276
|
|
*
|
1277
|
|
* 2015-05-14, 1.10
|
1278
|
|
*/
|
1279
|
1
|
if (DEPRECATE(
|
1280
|
|
"elementwise comparison failed; "
|
1281
|
|
"this will raise an error in the future.") < 0) {
|
1282
|
|
goto fail;
|
1283
|
|
}
|
1284
|
|
}
|
1285
|
1
|
Py_XDECREF(exc);
|
1286
|
1
|
Py_XDECREF(val);
|
1287
|
1
|
Py_XDECREF(tb);
|
1288
|
1
|
Py_INCREF(Py_NotImplemented);
|
1289
|
1
|
return Py_NotImplemented;
|
1290
|
|
}
|
1291
|
1
|
else if (other_is_flexible || self_is_flexible) {
|
1292
|
|
/*
|
1293
|
|
* For LE, LT, GT, GE and a flexible self or other, we return
|
1294
|
|
* NotImplemented, which is the correct answer since the ufuncs do
|
1295
|
|
* not in fact implement loops for those. This will get us the
|
1296
|
|
* desired TypeError.
|
1297
|
|
*/
|
1298
|
1
|
Py_XDECREF(exc);
|
1299
|
1
|
Py_XDECREF(val);
|
1300
|
1
|
Py_XDECREF(tb);
|
1301
|
1
|
Py_INCREF(Py_NotImplemented);
|
1302
|
1
|
return Py_NotImplemented;
|
1303
|
|
}
|
1304
|
|
else {
|
1305
|
|
/* LE, LT, GT, or GE with non-flexible other; just pass on error */
|
1306
|
|
goto fail;
|
1307
|
|
}
|
1308
|
|
|
1309
|
1
|
fail:
|
1310
|
|
/*
|
1311
|
|
* Reraise the original exception, possibly chaining with a new one.
|
1312
|
|
*/
|
1313
|
1
|
npy_PyErr_ChainExceptionsCause(exc, val, tb);
|
1314
|
1
|
return NULL;
|
1315
|
|
}
|
1316
|
|
|
1317
|
|
NPY_NO_EXPORT PyObject *
|
1318
|
1
|
array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op)
|
1319
|
|
{
|
1320
|
|
PyArrayObject *array_other;
|
1321
|
1
|
PyObject *obj_self = (PyObject *)self;
|
1322
|
1
|
PyObject *result = NULL;
|
1323
|
|
|
1324
|
|
/* Special case for string arrays (which don't and currently can't have
|
1325
|
|
* ufunc loops defined, so there's no point in trying).
|
1326
|
|
*/
|
1327
|
1
|
if (PyArray_ISSTRING(self)) {
|
1328
|
1
|
array_other = (PyArrayObject *)PyArray_FromObject(other,
|
1329
|
|
NPY_NOTYPE, 0, 0);
|
1330
|
1
|
if (array_other == NULL) {
|
1331
|
0
|
PyErr_Clear();
|
1332
|
|
/* Never mind, carry on, see what happens */
|
1333
|
|
}
|
1334
|
1
|
else if (!PyArray_ISSTRING(array_other)) {
|
1335
|
1
|
Py_DECREF(array_other);
|
1336
|
|
/* Never mind, carry on, see what happens */
|
1337
|
|
}
|
1338
|
|
else {
|
1339
|
1
|
result = _strings_richcompare(self, array_other, cmp_op, 0);
|
1340
|
1
|
Py_DECREF(array_other);
|
1341
|
|
return result;
|
1342
|
|
}
|
1343
|
|
/* If we reach this point, it means that we are not comparing
|
1344
|
|
* string-to-string. It's possible that this will still work out,
|
1345
|
|
* e.g. if the other array is an object array, then both will be cast
|
1346
|
|
* to object or something? I don't know how that works actually, but
|
1347
|
|
* it does, b/c this works:
|
1348
|
|
* l = ["a", "b"]
|
1349
|
|
* assert np.array(l, dtype="S1") == np.array(l, dtype="O")
|
1350
|
|
* So we fall through and see what happens.
|
1351
|
|
*/
|
1352
|
|
}
|
1353
|
|
|
1354
|
1
|
switch (cmp_op) {
|
1355
|
1
|
case Py_LT:
|
1356
|
1
|
RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other);
|
1357
|
1
|
result = PyArray_GenericBinaryFunction(self, other, n_ops.less);
|
1358
|
1
|
break;
|
1359
|
1
|
case Py_LE:
|
1360
|
1
|
RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other);
|
1361
|
1
|
result = PyArray_GenericBinaryFunction(self, other, n_ops.less_equal);
|
1362
|
1
|
break;
|
1363
|
1
|
case Py_EQ:
|
1364
|
1
|
RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other);
|
1365
|
|
/*
|
1366
|
|
* The ufunc does not support void/structured types, so these
|
1367
|
|
* need to be handled specifically. Only a few cases are supported.
|
1368
|
|
*/
|
1369
|
|
|
1370
|
1
|
if (PyArray_TYPE(self) == NPY_VOID) {
|
1371
|
|
int _res;
|
1372
|
|
|
1373
|
1
|
array_other = (PyArrayObject *)PyArray_FROM_O(other);
|
1374
|
|
/*
|
1375
|
|
* If not successful, indicate that the items cannot be compared
|
1376
|
|
* this way.
|
1377
|
|
*/
|
1378
|
1
|
if (array_other == NULL) {
|
1379
|
|
/* 2015-05-07, 1.10 */
|
1380
|
0
|
if (DEPRECATE_silence_error(
|
1381
|
|
"elementwise == comparison failed and returning scalar "
|
1382
|
|
"instead; this will raise an error in the future.") < 0) {
|
1383
|
|
return NULL;
|
1384
|
|
}
|
1385
|
0
|
Py_INCREF(Py_NotImplemented);
|
1386
|
0
|
return Py_NotImplemented;
|
1387
|
|
}
|
1388
|
|
|
1389
|
1
|
_res = PyArray_CanCastTypeTo(PyArray_DESCR(self),
|
1390
|
|
PyArray_DESCR(array_other),
|
1391
|
|
NPY_EQUIV_CASTING);
|
1392
|
1
|
if (_res == 0) {
|
1393
|
|
/* 2015-05-07, 1.10 */
|
1394
|
1
|
Py_DECREF(array_other);
|
1395
|
1
|
if (DEPRECATE_FUTUREWARNING(
|
1396
|
|
"elementwise == comparison failed and returning scalar "
|
1397
|
|
"instead; this will raise an error or perform "
|
1398
|
|
"elementwise comparison in the future.") < 0) {
|
1399
|
|
return NULL;
|
1400
|
|
}
|
1401
|
1
|
Py_INCREF(Py_False);
|
1402
|
1
|
return Py_False;
|
1403
|
|
}
|
1404
|
|
else {
|
1405
|
1
|
result = _void_compare(self, array_other, cmp_op);
|
1406
|
|
}
|
1407
|
1
|
Py_DECREF(array_other);
|
1408
|
|
return result;
|
1409
|
|
}
|
1410
|
|
|
1411
|
1
|
result = PyArray_GenericBinaryFunction(self,
|
1412
|
|
(PyObject *)other,
|
1413
|
|
n_ops.equal);
|
1414
|
1
|
break;
|
1415
|
1
|
case Py_NE:
|
1416
|
1
|
RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other);
|
1417
|
|
/*
|
1418
|
|
* The ufunc does not support void/structured types, so these
|
1419
|
|
* need to be handled specifically. Only a few cases are supported.
|
1420
|
|
*/
|
1421
|
|
|
1422
|
1
|
if (PyArray_TYPE(self) == NPY_VOID) {
|
1423
|
|
int _res;
|
1424
|
|
|
1425
|
1
|
array_other = (PyArrayObject *)PyArray_FROM_O(other);
|
1426
|
|
/*
|
1427
|
|
* If not successful, indicate that the items cannot be compared
|
1428
|
|
* this way.
|
1429
|
|
*/
|
1430
|
1
|
if (array_other == NULL) {
|
1431
|
|
/* 2015-05-07, 1.10 */
|
1432
|
0
|
if (DEPRECATE_silence_error(
|
1433
|
|
"elementwise != comparison failed and returning scalar "
|
1434
|
|
"instead; this will raise an error in the future.") < 0) {
|
1435
|
|
return NULL;
|
1436
|
|
}
|
1437
|
0
|
Py_INCREF(Py_NotImplemented);
|
1438
|
0
|
return Py_NotImplemented;
|
1439
|
|
}
|
1440
|
|
|
1441
|
1
|
_res = PyArray_CanCastTypeTo(PyArray_DESCR(self),
|
1442
|
|
PyArray_DESCR(array_other),
|
1443
|
|
NPY_EQUIV_CASTING);
|
1444
|
1
|
if (_res == 0) {
|
1445
|
|
/* 2015-05-07, 1.10 */
|
1446
|
1
|
Py_DECREF(array_other);
|
1447
|
1
|
if (DEPRECATE_FUTUREWARNING(
|
1448
|
|
"elementwise != comparison failed and returning scalar "
|
1449
|
|
"instead; this will raise an error or perform "
|
1450
|
|
"elementwise comparison in the future.") < 0) {
|
1451
|
|
return NULL;
|
1452
|
|
}
|
1453
|
1
|
Py_INCREF(Py_True);
|
1454
|
1
|
return Py_True;
|
1455
|
|
}
|
1456
|
|
else {
|
1457
|
1
|
result = _void_compare(self, array_other, cmp_op);
|
1458
|
1
|
Py_DECREF(array_other);
|
1459
|
|
}
|
1460
|
|
return result;
|
1461
|
|
}
|
1462
|
|
|
1463
|
1
|
result = PyArray_GenericBinaryFunction(self, (PyObject *)other,
|
1464
|
|
n_ops.not_equal);
|
1465
|
1
|
break;
|
1466
|
1
|
case Py_GT:
|
1467
|
1
|
RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other);
|
1468
|
1
|
result = PyArray_GenericBinaryFunction(self, other,
|
1469
|
|
n_ops.greater);
|
1470
|
1
|
break;
|
1471
|
1
|
case Py_GE:
|
1472
|
1
|
RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other);
|
1473
|
1
|
result = PyArray_GenericBinaryFunction(self, other,
|
1474
|
|
n_ops.greater_equal);
|
1475
|
1
|
break;
|
1476
|
0
|
default:
|
1477
|
0
|
Py_INCREF(Py_NotImplemented);
|
1478
|
0
|
return Py_NotImplemented;
|
1479
|
|
}
|
1480
|
1
|
if (result == NULL) {
|
1481
|
|
/*
|
1482
|
|
* 2015-05-14, 1.10; updated 2018-06-18, 1.16.
|
1483
|
|
*
|
1484
|
|
* Comparisons can raise errors when element-wise comparison is not
|
1485
|
|
* possible. Some of these, though, should not be passed on.
|
1486
|
|
* In particular, the ufuncs do not have loops for flexible dtype,
|
1487
|
|
* so those should be treated separately. Furthermore, for EQ and NE,
|
1488
|
|
* we should never fail.
|
1489
|
|
*
|
1490
|
|
* Our ideal behaviour would be:
|
1491
|
|
*
|
1492
|
|
* 1. For EQ and NE:
|
1493
|
|
* - If self and other are scalars, return NotImplemented,
|
1494
|
|
* so that python can assign True of False as appropriate.
|
1495
|
|
* - If either is an array, return an array of False or True.
|
1496
|
|
*
|
1497
|
|
* 2. For LT, LE, GE, GT:
|
1498
|
|
* - If self or other was flexible, return NotImplemented
|
1499
|
|
* (as is in fact the case), so python can raise a TypeError.
|
1500
|
|
* - If other is not convertible to an array, pass on the error
|
1501
|
|
* (MHvK, 2018-06-18: not sure about this, but it's what we have).
|
1502
|
|
*
|
1503
|
|
* However, for backwards compatibility, we cannot yet return arrays,
|
1504
|
|
* so we raise warnings instead.
|
1505
|
|
*/
|
1506
|
1
|
result = _failed_comparison_workaround(self, other, cmp_op);
|
1507
|
|
}
|
1508
|
|
return result;
|
1509
|
|
}
|
1510
|
|
|
1511
|
|
/*NUMPY_API
|
1512
|
|
*/
|
1513
|
|
NPY_NO_EXPORT int
|
1514
|
0
|
PyArray_ElementStrides(PyObject *obj)
|
1515
|
|
{
|
1516
|
|
PyArrayObject *arr;
|
1517
|
|
int itemsize;
|
1518
|
|
int i, ndim;
|
1519
|
|
npy_intp *strides;
|
1520
|
|
|
1521
|
0
|
if (!PyArray_Check(obj)) {
|
1522
|
|
return 0;
|
1523
|
|
}
|
1524
|
|
|
1525
|
0
|
arr = (PyArrayObject *)obj;
|
1526
|
|
|
1527
|
0
|
itemsize = PyArray_ITEMSIZE(arr);
|
1528
|
0
|
ndim = PyArray_NDIM(arr);
|
1529
|
0
|
strides = PyArray_STRIDES(arr);
|
1530
|
|
|
1531
|
0
|
for (i = 0; i < ndim; i++) {
|
1532
|
0
|
if ((strides[i] % itemsize) != 0) {
|
1533
|
|
return 0;
|
1534
|
|
}
|
1535
|
|
}
|
1536
|
|
return 1;
|
1537
|
|
}
|
1538
|
|
|
1539
|
|
/*
|
1540
|
|
* This routine checks to see if newstrides (of length nd) will not
|
1541
|
|
* ever be able to walk outside of the memory implied numbytes and offset.
|
1542
|
|
*
|
1543
|
|
* The available memory is assumed to start at -offset and proceed
|
1544
|
|
* to numbytes-offset. The strides are checked to ensure
|
1545
|
|
* that accessing memory using striding will not try to reach beyond
|
1546
|
|
* this memory for any of the axes.
|
1547
|
|
*
|
1548
|
|
* If numbytes is 0 it will be calculated using the dimensions and
|
1549
|
|
* element-size.
|
1550
|
|
*
|
1551
|
|
* This function checks for walking beyond the beginning and right-end
|
1552
|
|
* of the buffer and therefore works for any integer stride (positive
|
1553
|
|
* or negative).
|
1554
|
|
*/
|
1555
|
|
|
1556
|
|
/*NUMPY_API*/
|
1557
|
|
NPY_NO_EXPORT npy_bool
|
1558
|
1
|
PyArray_CheckStrides(int elsize, int nd, npy_intp numbytes, npy_intp offset,
|
1559
|
|
npy_intp const *dims, npy_intp const *newstrides)
|
1560
|
|
{
|
1561
|
|
npy_intp begin, end;
|
1562
|
|
npy_intp lower_offset;
|
1563
|
|
npy_intp upper_offset;
|
1564
|
|
|
1565
|
1
|
if (numbytes == 0) {
|
1566
|
1
|
numbytes = PyArray_MultiplyList(dims, nd) * elsize;
|
1567
|
|
}
|
1568
|
|
|
1569
|
1
|
begin = -offset;
|
1570
|
1
|
end = numbytes - offset;
|
1571
|
|
|
1572
|
1
|
offset_bounds_from_strides(elsize, nd, dims, newstrides,
|
1573
|
|
&lower_offset, &upper_offset);
|
1574
|
|
|
1575
|
1
|
if ((upper_offset > end) || (lower_offset < begin)) {
|
1576
|
|
return NPY_FALSE;
|
1577
|
|
}
|
1578
|
1
|
return NPY_TRUE;
|
1579
|
|
}
|
1580
|
|
|
1581
|
|
|
1582
|
|
static PyObject *
|
1583
|
1
|
array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
|
1584
|
|
{
|
1585
|
|
static char *kwlist[] = {"shape", "dtype", "buffer", "offset", "strides",
|
1586
|
|
"order", NULL};
|
1587
|
1
|
PyArray_Descr *descr = NULL;
|
1588
|
|
int itemsize;
|
1589
|
1
|
PyArray_Dims dims = {NULL, 0};
|
1590
|
1
|
PyArray_Dims strides = {NULL, -1};
|
1591
|
|
PyArray_Chunk buffer;
|
1592
|
1
|
npy_longlong offset = 0;
|
1593
|
1
|
NPY_ORDER order = NPY_CORDER;
|
1594
|
1
|
int is_f_order = 0;
|
1595
|
|
PyArrayObject *ret;
|
1596
|
|
|
1597
|
1
|
buffer.ptr = NULL;
|
1598
|
|
/*
|
1599
|
|
* Usually called with shape and type but can also be called with buffer,
|
1600
|
|
* strides, and swapped info For now, let's just use this to create an
|
1601
|
|
* empty, contiguous array of a specific type and shape.
|
1602
|
|
*/
|
1603
|
1
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&LO&O&:ndarray",
|
1604
|
|
kwlist, PyArray_IntpConverter,
|
1605
|
|
&dims,
|
1606
|
|
PyArray_DescrConverter,
|
1607
|
|
&descr,
|
1608
|
|
PyArray_BufferConverter,
|
1609
|
|
&buffer,
|
1610
|
|
&offset,
|
1611
|
|
&PyArray_OptionalIntpConverter,
|
1612
|
|
&strides,
|
1613
|
|
&PyArray_OrderConverter,
|
1614
|
|
&order)) {
|
1615
|
|
goto fail;
|
1616
|
|
}
|
1617
|
1
|
if (order == NPY_FORTRANORDER) {
|
1618
|
1
|
is_f_order = 1;
|
1619
|
|
}
|
1620
|
1
|
if (descr == NULL) {
|
1621
|
1
|
descr = PyArray_DescrFromType(NPY_DEFAULT_TYPE);
|
1622
|
|
}
|
1623
|
|
|
1624
|
1
|
itemsize = descr->elsize;
|
1625
|
|
|
1626
|
1
|
if (strides.len != -1) {
|
1627
|
|
npy_intp nb, off;
|
1628
|
1
|
if (strides.len != dims.len) {
|
1629
|
1
|
PyErr_SetString(PyExc_ValueError,
|
1630
|
|
"strides, if given, must be " \
|
1631
|
|
"the same length as shape");
|
1632
|
1
|
goto fail;
|
1633
|
|
}
|
1634
|
|
|
1635
|
1
|
if (buffer.ptr == NULL) {
|
1636
|
|
nb = 0;
|
1637
|
|
off = 0;
|
1638
|
|
}
|
1639
|
|
else {
|
1640
|
1
|
nb = buffer.len;
|
1641
|
1
|
off = (npy_intp) offset;
|
1642
|
|
}
|
1643
|
|
|
1644
|
|
|
1645
|
1
|
if (!PyArray_CheckStrides(itemsize, dims.len,
|
1646
|
|
nb, off,
|
1647
|
1
|
dims.ptr, strides.ptr)) {
|
1648
|
1
|
PyErr_SetString(PyExc_ValueError,
|
1649
|
|
"strides is incompatible " \
|
1650
|
|
"with shape of requested " \
|
1651
|
|
"array and size of buffer");
|
1652
|
1
|
goto fail;
|
1653
|
|
}
|
1654
|
|
}
|
1655
|
|
|
1656
|
1
|
if (buffer.ptr == NULL) {
|
1657
|
1
|
ret = (PyArrayObject *)
|
1658
|
1
|
PyArray_NewFromDescr_int(subtype, descr,
|
1659
|
|
(int)dims.len,
|
1660
|
1
|
dims.ptr,
|
1661
|
1
|
strides.ptr, NULL, is_f_order, NULL, NULL,
|
1662
|
|
0, 1);
|
1663
|
1
|
if (ret == NULL) {
|
1664
|
0
|
descr = NULL;
|
1665
|
0
|
goto fail;
|
1666
|
|
}
|
1667
|
1
|
if (PyDataType_FLAGCHK(descr, NPY_ITEM_HASOBJECT)) {
|
1668
|
|
/* place Py_None in object positions */
|
1669
|
1
|
PyArray_FillObjectArray(ret, Py_None);
|
1670
|
1
|
if (PyErr_Occurred()) {
|
1671
|
0
|
descr = NULL;
|
1672
|
0
|
goto fail;
|
1673
|
|
}
|
1674
|
|
}
|
1675
|
|
}
|
1676
|
|
else {
|
1677
|
|
/* buffer given -- use it */
|
1678
|
1
|
if (dims.len == 1 && dims.ptr[0] == -1) {
|
1679
|
0
|
dims.ptr[0] = (buffer.len-(npy_intp)offset) / itemsize;
|
1680
|
|
}
|
1681
|
1
|
else if ((strides.ptr == NULL) &&
|
1682
|
1
|
(buffer.len < (offset + (((npy_intp)itemsize)*
|
1683
|
1
|
PyArray_MultiplyList(dims.ptr,
|
1684
|
|
dims.len))))) {
|
1685
|
1
|
PyErr_SetString(PyExc_TypeError,
|
1686
|
|
"buffer is too small for " \
|
1687
|
|
"requested array");
|
1688
|
1
|
goto fail;
|
1689
|
|
}
|
1690
|
|
/* get writeable and aligned */
|
1691
|
1
|
if (is_f_order) {
|
1692
|
1
|
buffer.flags |= NPY_ARRAY_F_CONTIGUOUS;
|
1693
|
|
}
|
1694
|
1
|
ret = (PyArrayObject *)PyArray_NewFromDescr_int(
|
1695
|
|
subtype, descr,
|
1696
|
1
|
dims.len, dims.ptr, strides.ptr, offset + (char *)buffer.ptr,
|
1697
|
|
buffer.flags, NULL, buffer.base,
|
1698
|
|
0, 1);
|
1699
|
1
|
if (ret == NULL) {
|
1700
|
1
|
descr = NULL;
|
1701
|
1
|
goto fail;
|
1702
|
|
}
|
1703
|
|
}
|
1704
|
|
|
1705
|
1
|
npy_free_cache_dim_obj(dims);
|
1706
|
1
|
npy_free_cache_dim_obj(strides);
|
1707
|
1
|
return (PyObject *)ret;
|
1708
|
|
|
1709
|
1
|
fail:
|
1710
|
1
|
Py_XDECREF(descr);
|
1711
|
1
|
npy_free_cache_dim_obj(dims);
|
1712
|
1
|
npy_free_cache_dim_obj(strides);
|
1713
|
1
|
return NULL;
|
1714
|
|
}
|
1715
|
|
|
1716
|
|
|
1717
|
|
static PyObject *
|
1718
|
1
|
array_iter(PyArrayObject *arr)
|
1719
|
|
{
|
1720
|
1
|
if (PyArray_NDIM(arr) == 0) {
|
1721
|
0
|
PyErr_SetString(PyExc_TypeError,
|
1722
|
|
"iteration over a 0-d array");
|
1723
|
0
|
return NULL;
|
1724
|
|
}
|
1725
|
1
|
return PySeqIter_New((PyObject *)arr);
|
1726
|
|
}
|
1727
|
|
|
1728
|
|
static PyObject *
|
1729
|
1
|
array_alloc(PyTypeObject *type, Py_ssize_t NPY_UNUSED(nitems))
|
1730
|
|
{
|
1731
|
|
/* nitems will always be 0 */
|
1732
|
1
|
PyObject *obj = PyObject_Malloc(type->tp_basicsize);
|
1733
|
1
|
PyObject_Init(obj, type);
|
1734
|
1
|
return obj;
|
1735
|
|
}
|
1736
|
|
|
1737
|
|
static void
|
1738
|
1
|
array_free(PyObject * v)
|
1739
|
|
{
|
1740
|
|
/* avoid same deallocator as PyBaseObject, see gentype_free */
|
1741
|
1
|
PyObject_Free(v);
|
1742
|
|
}
|
1743
|
|
|
1744
|
|
|
1745
|
|
NPY_NO_EXPORT PyTypeObject PyArray_Type = {
|
1746
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
1747
|
|
.tp_name = "numpy.ndarray",
|
1748
|
|
.tp_basicsize = NPY_SIZEOF_PYARRAYOBJECT,
|
1749
|
|
/* methods */
|
1750
|
|
.tp_dealloc = (destructor)array_dealloc,
|
1751
|
|
.tp_repr = (reprfunc)array_repr,
|
1752
|
|
.tp_as_number = &array_as_number,
|
1753
|
|
.tp_as_sequence = &array_as_sequence,
|
1754
|
|
.tp_as_mapping = &array_as_mapping,
|
1755
|
|
/*
|
1756
|
|
* The tp_hash slot will be set PyObject_HashNotImplemented when the
|
1757
|
|
* module is loaded.
|
1758
|
|
*/
|
1759
|
|
.tp_str = (reprfunc)array_str,
|
1760
|
|
.tp_as_buffer = &array_as_buffer,
|
1761
|
|
.tp_flags =(Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE),
|
1762
|
|
|
1763
|
|
.tp_richcompare = (richcmpfunc)array_richcompare,
|
1764
|
|
.tp_weaklistoffset = offsetof(PyArrayObject_fields, weakreflist),
|
1765
|
|
.tp_iter = (getiterfunc)array_iter,
|
1766
|
|
.tp_methods = array_methods,
|
1767
|
|
.tp_getset = array_getsetlist,
|
1768
|
|
.tp_alloc = (allocfunc)array_alloc,
|
1769
|
|
.tp_new = (newfunc)array_new,
|
1770
|
|
.tp_free = (freefunc)array_free,
|
1771
|
|
};
|