comparison PyTypeInterface.cpp @ 32:a8231788216c vampy2

Vampy2: accept numpy array return types.
author fazekasgy
date Mon, 21 Sep 2009 13:56:28 +0000
parents 4f1894c7591b
children c4da8d559872
comparison
equal deleted inserted replaced
31:4f1894c7591b 32:a8231788216c
1 /* 1 /*
2 */ 2 */
3 3
4 #include <Python.h> 4 #include <Python.h>
5 #ifdef HAVE_NUMPY
6 #include "arrayobject.h"
7 #endif
5 #include "PyTypeInterface.h" 8 #include "PyTypeInterface.h"
6 #include "PyRealTime.h" 9 #include "PyRealTime.h"
7 #include "PyExtensionModule.h" 10 #include "PyExtensionModule.h"
8 #include <math.h> 11 #include <math.h>
9 #include <float.h> 12 #include <float.h>
23 static std::map<std::string, eSampleTypes> sampleKeys; 26 static std::map<std::string, eSampleTypes> sampleKeys;
24 static std::map<std::string, eFeatureFields> ffKeys; 27 static std::map<std::string, eFeatureFields> ffKeys;
25 static bool isMapInitialised = false; 28 static bool isMapInitialised = false;
26 29
27 /* Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS 30 /* Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS
28 (EXCEPT FOR TEMPORARY PYOBJECTS)! */ 31 (EXCEPT FOR TEMPORARY PYTHON OBJECTS)! */
29 32
30 PyTypeInterface::PyTypeInterface() : 33 PyTypeInterface::PyTypeInterface() :
31 m_strict(false), 34 m_strict(false),
32 m_error(false), 35 m_error(false),
33 m_lastError(m_noError), 36 m_lastError(m_noError),
403 Output.push_back(ListElement); 406 Output.push_back(ListElement);
404 } 407 }
405 return Output; 408 return Output;
406 } 409 }
407 410
408 //convert Python list to C++ vector of floats 411 //convert PyFeature.value (typically a list or numpy array) to C++ vector of floats
409 std::vector<float> 412 std::vector<float>
410 PyTypeInterface::PyValue_To_FloatVector (PyObject *inputList) const 413 PyTypeInterface::PyValue_To_FloatVector (PyObject *pyValue) const
411 { 414 {
412 typedef std::vector<float> floatVector;
413 std::vector<float> Output; 415 std::vector<float> Output;
414 416
415 /// Check for NumPy Array 417 #ifdef HAVE_NUMPY
416 if (PyObject_HasAttrString(inputList,"__array_struct__")) { 418 /// Check for NumPy Array: this requires linking with numpy
417 int vectorLength; 419 /// but, we don't really need this macro
418 float *dataptr = getNumPyObjectData(inputList,vectorLength); 420 // if (PyArray_CheckExact(inputList)) cerr << "PyPyArray_CheckExact OK" << endl;
419 if (dataptr != 0) cerr << "Numpy array found: " << vectorLength << endl; 421
420 // Output = *dataptr; 422 /// numpy array
421 } 423 if (PyObject_HasAttrString(pyValue,"__array_struct__")) {
424 return PyArray_To_FloatVector(pyValue);
425 }
426 #endif
427
428 /// python list
429 if (PyList_Check(pyValue)) {
430 return PyList_To_FloatVector(pyValue);
431 }
432
433 /// assume a single number
434 /// this allows to write e.g. Feature.values = 5 instead of [5.00]
435 Output.push_back(PyValue_To_Float(pyValue));
436 return Output;
437
438 /// TODO : set error
439
440 }
441
442 //convert a list of python floats
443 std::vector<float>
444 PyTypeInterface::PyList_To_FloatVector (PyObject *inputList) const
445 {
446 std::vector<float> Output;
422 447
423 float ListElement; 448 float ListElement;
424 PyObject *pyFloat = NULL; 449 PyObject *pyFloat = NULL;
425 450
426 if (!PyList_Check(inputList)) return Output; 451 if (!PyList_Check(inputList)) return Output;
427 452
428 for (Py_ssize_t k = 0; k < PyList_GET_SIZE(inputList); ++k) { 453 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
429 //Get next list item (Borrowed Reference) 454 //Get next list item (Borrowed Reference)
430 pyFloat = PyList_GET_ITEM(inputList,k); 455 pyFloat = PyList_GET_ITEM(inputList,i);
431 ListElement = (float) PyFloat_AS_DOUBLE(pyFloat); 456 ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
432 #ifdef _DEBUG 457 #ifdef _DEBUG
433 cerr << "value: " << ListElement << endl; 458 cerr << "value: " << ListElement << endl;
434 #endif 459 #endif
435 Output.push_back(ListElement); 460 Output.push_back(ListElement);
436 } 461 }
437 462
438 return Output; 463 return Output;
439 } 464 }
440 465
466 #ifdef HAVE_NUMPY
467 std::vector<float>
468 PyTypeInterface::PyArray_To_FloatVector (PyObject *pyValue) const
469 {
470 std::vector<float> Output;
471
472 /// we don't verify the array here as it'd be duplicated mostly
473 // if (!PyObject_HasAttrString(pyValue,"__array_struct__")) {
474 // return Output;
475 // }
476
477 PyArrayObject* pyArray = (PyArrayObject*) pyValue;
478 PyArray_Descr* descr = pyArray->descr;
479
480 /// check raw data pointer
481 if (pyArray->data == 0) return Output;
482
483 /// check dimensions
484 if (pyArray->nd != 1) {
485 cerr << "Error: array must be 1D" << endl;
486 return Output;
487 }
488
489 #ifdef _DEBUG
490 cerr << "Numpy array verified." << endl;
491 #endif
492
493 switch (descr->type_num)
494 {
495 case NPY_FLOAT :
496 return PyArray_Convert<float,float>(pyArray->data,pyArray->dimensions[0]);
497 case NPY_DOUBLE :
498 return PyArray_Convert<float,double>(pyArray->data,pyArray->dimensions[0]);
499 case NPY_INT :
500 return PyArray_Convert<float,int>(pyArray->data,pyArray->dimensions[0]);
501 case NPY_LONG :
502 return PyArray_Convert<float,long>(pyArray->data,pyArray->dimensions[0]);
503
504 default :
505 cerr << "Error. Unsupported element type in NumPy array object." << endl;
506 return Output;
507 }
508 }
509 #endif
441 510
442 /* Vamp API Specific Types 511 /* Vamp API Specific Types
443 512
444 Vamp::Plugin::OutputList 513 Vamp::Plugin::OutputList
445 PyTypeInterface::PyValue_To_OutputList(PyObject* pyList) const 514 PyTypeInterface::PyValue_To_OutputList(PyObject* pyList) const
578 647
579 /// FeatureSet (an int map of OutputLists) 648 /// FeatureSet (an int map of OutputLists)
580 Vamp::Plugin::FeatureSet 649 Vamp::Plugin::FeatureSet
581 PyTypeInterface::PyValue_To_FeatureSet(PyObject* pyValue) const 650 PyTypeInterface::PyValue_To_FeatureSet(PyObject* pyValue) const
582 { 651 {
583 Vamp::Plugin::FeatureSet rFeatureSet; /// PyFeatureSet is an int map 652 Vamp::Plugin::FeatureSet rFeatureSet; /// map<int>
584 if (pyValue == NULL) { 653 if (pyValue == NULL) {
585 cerr << "NULL FeatureSet" << endl; 654 cerr << "NULL FeatureSet" << endl;
586 return rFeatureSet; 655 return rFeatureSet;
587 } 656 }
588 657
890 return PyTypeInterface::ValueError(); 959 return PyTypeInterface::ValueError();
891 } 960 }
892 } 961 }
893 962
894 /* Utilities */ 963 /* Utilities */
895
896 //return a pointer to the data in the numPy array
897 float*
898 PyTypeInterface::getNumPyObjectData(PyObject *object, int &length) const
899 {
900
901 char attr_name[]="__array_struct__";
902
903 //check if we passed in a NumPy array object
904 if (!PyObject_HasAttrString(object,attr_name)) {
905 // PyErr_SetString(PyExc_TypeError,
906 // "Input object has no __array_struct__ attribute. NumPy array required.");
907 return NULL;
908 }
909
910 //retrieve __array_struct__ interface
911 object = PyObject_GetAttrString(object,attr_name);
912
913 //check whether we found CObjects
914 if (!PyCObject_Check(object)) {
915 PyErr_SetString(PyExc_TypeError,
916 "The passed __array_struct__ interface is not a valid C Object.");
917 return NULL;
918 }
919
920
921 //check if the pointers directed to the integer '2'
922 int *check = (int *) PyCObject_AsVoidPtr (object);
923
924 if (*check != 2 ) {
925 PyErr_SetString(PyExc_TypeError,
926 "A C Object __array_struct__ required as inputs");
927 return NULL;
928 }
929
930 //convert CObjects to Array interfaces
931 PyArrayInterface *arrayInterface =
932 (PyArrayInterface *) PyCObject_AsVoidPtr (object);
933
934 //check array dimension: should be 1
935 int inputDim = arrayInterface->nd;
936
937 if (inputDim > 1 ) {
938 PyErr_SetString(PyExc_TypeError,
939 "Array dimensions must not exceed one.");
940 return NULL;
941 }
942
943 // check if vector size is sane
944 Py_intptr_t arrayLength = arrayInterface->shape[0];
945 length = (int) arrayLength;
946
947 // if (arrayLength < 8 || arrayLength > 65536 ) {
948 // PyErr_SetString(PyExc_TypeError,
949 // "Array length is out of bounds.");
950 // return NULL;
951 // }
952
953 //check type; must be float32
954 char arrayType = arrayInterface->typekind;
955
956 if (arrayType != 'f' ) {
957 PyErr_SetString(PyExc_TypeError,
958 "Floating point arrays required.");
959 return NULL;
960 }
961
962 //return data vector address
963 return (float*) arrayInterface->data;
964
965 }
966 964
967 /// get the type name of an object 965 /// get the type name of an object
968 std::string 966 std::string
969 PyTypeInterface::PyValue_Get_TypeName(PyObject* pyValue) const 967 PyTypeInterface::PyValue_Get_TypeName(PyObject* pyValue) const
970 { 968 {