46
53
/* This routine assumes that y->owner is true (and so y is contiguous) */
47
54
static void _fff_vector_copy_fromPtr( fff_vector* y, const char* data, npy_intp stride, int type )
49
npy_intp dim = (npy_intp) y->size;
50
PyArrayObject* x = (PyArrayObject*) PyArray_New( &PyArray_Type, 1, &dim, type, &stride,
51
(void*)data, 0, NPY_BEHAVED, NULL );
52
PyArrayObject* xd = (PyArrayObject*) PyArray_SimpleNewFromData( 1, &dim, NPY_DOUBLE, (void*)y->data );
56
npy_intp dim[1] = {(npy_intp)y->size};
57
npy_intp strides[1] = {stride};
58
PyArrayObject* x = (PyArrayObject*) PyArray_New( &PyArray_Type, 1, dim, type, strides,
59
(void*)data, 0, NPY_CARRAY, NULL );
60
PyArrayObject* xd = (PyArrayObject*) PyArray_SimpleNewFromData( 1, dim, NPY_DOUBLE, (void*)y->data );
53
61
PyArray_CastTo( xd, x );
257
265
/** Static routines **/
259
static fff_vector* _fff_vector_fromPyArrayIter( const PyArrayIterObject* it, npy_intp axis )
262
char* data = PyArray_ITER_DATA( it );
263
PyArrayObject* ao = (PyArrayObject*) it->ao;
264
npy_intp dim = PyArray_DIM( ao, axis );
265
npy_intp stride = PyArray_STRIDE( ao, axis );
266
int type = PyArray_TYPE( ao );
267
int isaligned = PyArray_ISALIGNED( ao );
269
y = _fff_vector_fromPtr( data, dim, stride, type, isaligned );
274
static void _fff_vector_fromPyArrayIter_update( fff_vector* y, const PyArrayIterObject* it, npy_intp axis )
276
/* Case owner (PyArray non-DOUBLE): copy data */
278
PyArrayObject* ao = (PyArrayObject*) it->ao;
279
_fff_vector_copy_fromPtr( y, PyArray_ITER_DATA(it),
280
PyArray_STRIDE(ao, axis), PyArray_TYPE(ao) );
283
/* Case non-owner (PyArray DOUBLE): borrow data */
285
y->data = (double*) PyArray_ITER_DATA( it );
290
/* y->owner assumed true */
291
static void _fff_vector_toPyArrayIter_update( const fff_vector* y, PyArrayIterObject* it, npy_intp axis )
293
npy_intp dims[1], strides[1];
294
PyArrayObject* ao = (PyArrayObject*) it->ao;
295
dims[0] = (npy_intp) y->size;
296
strides[0] = PyArray_STRIDE(ao, axis);
298
/* Encapsulate y into a PyArray */
299
PyArrayObject* Py_y = (PyArrayObject*) PyArray_SimpleNewFromData( 1, dims, NPY_DOUBLE, (void*)y->data );
301
/* Current view of the PyArray along axis */
302
PyArrayObject* Py_view = (PyArrayObject*) PyArray_New( &PyArray_Type, 1, dims, PyArray_TYPE(ao), strides,
303
(void*)PyArray_ITER_DATA(it), 0, NPY_BEHAVED, NULL );
305
/* Copy (with cast) Py_y into Py_view */
306
PyArray_CastTo( Py_view, Py_y );
309
Py_XDECREF( Py_view );
317
fff_func_iterator* fff_func_iterator_new( npy_intp nargout, PyArrayObject** argout,
318
npy_intp nargin, PyArrayObject** argin,
321
fff_func_iterator* thisone;
323
PyArrayObject *Py_ptr;
324
int axis = (int)npy_axis; /* For compatibility with the new PyArray_IterAllButAxis API */
326
/* Create this one */
327
thisone = (fff_func_iterator*)malloc( sizeof(fff_func_iterator) );
328
if ( thisone == NULL )
331
/* Number of args and axis */
332
thisone->nargin = nargin;
333
thisone->nargout = nargout;
334
thisone->axis = axis;
336
/* Number of loop items */
337
/* TODO: add consistency check -- all arrays should have same dim except in the axis direction */
339
thisone->nitems = PyArray_SIZE(Py_ptr) / PyArray_DIM(Py_ptr, axis);
341
/* Allocate local objects (array iterators and local gsl vectors)*/
343
thisone->PyIter_argout = (PyArrayIterObject**)malloc( nargout*sizeof(PyArrayIterObject*) );
344
thisone->fff_argout = (fff_vector**)malloc( nargout*sizeof(fff_vector*) );
345
for( i=0; i<nargout; i++ ) {
346
thisone->PyIter_argout[i] = (PyArrayIterObject*)PyArray_IterAllButAxis( (PyObject*)argout[i], &axis );
347
thisone->fff_argout[i] = _fff_vector_fromPyArrayIter( thisone->PyIter_argout[i], axis );
350
thisone->PyIter_argin = (PyArrayIterObject**)malloc( nargin*sizeof(PyArrayIterObject*) );
351
thisone->fff_argin = (fff_vector**)malloc( nargin*sizeof(fff_vector*) );
352
for( i=0; i<nargin; i++ ) {
353
thisone->PyIter_argin[i] = (PyArrayIterObject*)PyArray_IterAllButAxis( (PyObject*)argin[i], &axis );
354
thisone->fff_argin[i] = _fff_vector_fromPyArrayIter( thisone->PyIter_argin[i], axis );
362
void fff_func_iterator_delete( fff_func_iterator* thisone )
366
for( i=0; i<thisone->nargout; i++ ) {
367
Py_XDECREF( thisone->PyIter_argout[i] );
368
fff_vector_delete( thisone->fff_argout[i] );
370
for( i=0; i<thisone->nargin; i++ ) {
371
Py_XDECREF( thisone->PyIter_argin[i] );
372
fff_vector_delete( thisone->fff_argin[i] );
374
free( thisone->PyIter_argout );
375
free( thisone->fff_argout );
376
free( thisone->PyIter_argin );
377
free( thisone->fff_argin );
386
void fff_func_iterator_eval( fff_func_iterator* thisone,
387
void (*func)( fff_vector**, fff_vector**, void* ),
391
npy_intp nargout = thisone->nargout, nargin = thisone->nargin, axis = thisone->axis;
392
PyArrayIterObject** PyIter_argout = thisone->PyIter_argout;
393
fff_vector** fff_argout = thisone->fff_argout;
394
PyArrayIterObject** PyIter_argin = thisone->PyIter_argin;
395
fff_vector** fff_argin = thisone->fff_argin;
396
PyArrayIterObject *PyIter_ptr;
399
/* Loop over items */
400
while( PyIter_argin[0]->index < thisone->nitems ) {
402
/* Do the job for current item */
403
func( fff_argout, fff_argin, par );
405
/* Prepare next item */
406
for( i=0; i<nargout; i++ ) {
407
PyIter_ptr = PyIter_argout[i];
408
fff_ptr = fff_argout[i];
410
/* If the gsl vector is not a view (owner), then push back its content */
411
if ( fff_ptr->owner )
412
_fff_vector_toPyArrayIter_update( fff_ptr, PyIter_ptr, axis );
414
PyArray_ITER_NEXT( PyIter_ptr );
415
_fff_vector_fromPyArrayIter_update( fff_ptr, PyIter_ptr, axis );
417
for( i=0; i<nargin; i++ ) {
418
PyIter_ptr = PyIter_argin[i];
419
PyArray_ITER_NEXT( PyIter_ptr );
420
_fff_vector_fromPyArrayIter_update( fff_argin[i], PyIter_ptr, axis );
423
} /* End loop over items */
430
void fff_func_iterator_reset( fff_func_iterator* thisone )
433
npy_intp nargout = thisone->nargout, nargin = thisone->nargin, axis = thisone->axis;
434
PyArrayIterObject** PyIter_argout = thisone->PyIter_argout;
435
fff_vector** fff_argout = thisone->fff_argout;
436
PyArrayIterObject** PyIter_argin = thisone->PyIter_argin;
437
fff_vector** fff_argin = thisone->fff_argin;
438
PyArrayIterObject *PyIter_ptr;
441
for( i=0; i<nargout; i++ ) {
442
PyIter_ptr = PyIter_argout[i];
443
fff_ptr = fff_argout[i];
444
PyArray_ITER_RESET( PyIter_ptr );
445
_fff_vector_fromPyArrayIter_update( fff_ptr, PyIter_ptr, axis );
447
for( i=0; i<nargin; i++ ) {
448
PyIter_ptr = PyIter_argin[i];
449
fff_ptr = fff_argin[i];
450
PyArray_ITER_RESET( PyIter_ptr );
451
_fff_vector_fromPyArrayIter_update( fff_ptr, PyIter_ptr, axis );
453
Create a PyArrayMultiArrayIter so as to iterate simultaneously on
454
several arrays except in one common axis. This is a
455
PyArrayMultiArrayIter constructor that I would like to see in the
456
numpy C API, but for now it is "hosted" in fffPy.h
458
TODO: check dimensions.
462
PyObject* PyArray_MultiIterAllButAxis( int n, int axis, ... )
465
PyArrayMultiIterObject *multi;
471
if (n < 2 || n > NPY_MAXARGS) {
472
PyErr_Format(PyExc_ValueError,
473
"Need between 2 and (%d) " \
474
"array objects (inclusive).", NPY_MAXARGS);
478
/* fprintf(stderr, "multi new...");*/
480
multi = (PyArrayMultiIterObject *) malloc(sizeof(PyArrayMultiIterObject));
481
if (multi == NULL) return PyErr_NoMemory();
482
PyObject_Init((PyObject *)multi, &PyArrayMultiIter_Type);
484
for (i=0; i<n; i++) multi->iters[i] = NULL;
489
for (i=0; i<n; i++) {
490
current = va_arg(va, PyObject *);
491
arr = PyArray_FROM_O(current);
496
multi->iters[i] = (PyArrayIterObject *)PyArray_IterAllButAxis(arr, &axis);
503
/*if (!err && PyArray_Broadcast(multi) < 0) err=1;*/
510
PyArray_MultiIter_RESET(multi);
512
return (PyObject *)multi;
516
/* Create an fff_vector from a PyArrayIter object */
517
fff_vector* fff_vector_fromPyArrayIter( const PyArrayIterObject* it, npy_intp axis )
520
char* data = PyArray_ITER_DATA( it );
521
PyArrayObject* ao = (PyArrayObject*) it->ao;
522
npy_intp dim = PyArray_DIM( ao, axis );
523
npy_intp stride = PyArray_STRIDE( ao, axis );
524
int type = PyArray_TYPE( ao );
525
int isaligned = PyArray_ISALIGNED( ao );
527
y = _fff_vector_fromPtr( data, dim, stride, type, isaligned );
532
/* Fetch vector data in an iterator */
533
void fff_vector_get_fromPyArrayIter( fff_vector* y, const PyArrayIterObject* it, npy_intp axis )
535
/* Case owner (PyArray non-DOUBLE): copy data */
537
PyArrayObject* ao = (PyArrayObject*) it->ao;
538
_fff_vector_copy_fromPtr( y, PyArray_ITER_DATA(it),
539
PyArray_STRIDE(ao, axis), PyArray_TYPE(ao) );
542
/* Case non-owner (PyArray DOUBLE): borrow data */
544
y->data = (double*) PyArray_ITER_DATA( it );
549
/* y assumed owner (otherwise, there is no point to call this function) */
550
void fff_vector_const_toPyArrayIter( const fff_vector* y, PyArrayIterObject* it, npy_intp axis )
555
npy_intp dims[1], strides[1];
556
PyArrayObject* ao = (PyArrayObject*) it->ao;
557
dims[0] = (npy_intp) y->size;
558
strides[0] = PyArray_STRIDE(ao, axis);
560
/* Encapsulate y into a PyArray */
561
PyArrayObject* Py_y = (PyArrayObject*) PyArray_SimpleNewFromData( 1, dims, NPY_DOUBLE, (void*)y->data );
563
/* Current view of the PyArray along axis */
564
PyArrayObject* Py_view = (PyArrayObject*) PyArray_New( &PyArray_Type, 1, dims, PyArray_TYPE(ao), strides,
565
(void*)PyArray_ITER_DATA(it), 0, NPY_BEHAVED, NULL );
567
/* Copy (with cast) Py_y into Py_view */
568
PyArray_CastTo( Py_view, Py_y );
571
Py_XDECREF( Py_view );