Mercurial > hg > vampy
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 { |