00001
00002
00003
00004
00005
00006 #define PY_ARRAY_UNIQUE_SYMBOL HippoPyArrayHandle
00007 #define NO_IMPORT_ARRAY
00008 #include "num_util.h"
00009
00010 namespace { const char* rcsid = "$Id: num__util_8cpp-source.html,v 1.36 2007/07/26 18:21:57 pfkeb Exp $"; }
00011
00012 using namespace boost::python;
00013
00014 namespace num_util{
00015
00016
00017
00018
00019 template <>
00020 PyArray_TYPES getEnum<unsigned char>(void)
00021 {
00022 return PyArray_UBYTE;
00023 }
00024
00025
00026 template <>
00027 PyArray_TYPES getEnum<signed char>(void)
00028 {
00029 #ifdef HAVE_NUMPY
00030 return PyArray_BYTE;
00031 #else
00032 return PyArray_SBYTE;
00033 #endif
00034 }
00035
00036 template <>
00037 PyArray_TYPES getEnum<short>(void)
00038 {
00039 return PyArray_SHORT;
00040 }
00041
00042 template <>
00043 PyArray_TYPES getEnum<unsigned short>(void)
00044 {
00045 return PyArray_USHORT;
00046 }
00047
00048
00049 template <>
00050 PyArray_TYPES getEnum<unsigned int>(void)
00051 {
00052 return PyArray_UINT;
00053 }
00054
00055 template <>
00056 PyArray_TYPES getEnum<int>(void)
00057 {
00058 return PyArray_INT;
00059 }
00060
00061 template <>
00062 PyArray_TYPES getEnum<long>(void)
00063 {
00064 return PyArray_LONG;
00065 }
00066
00067 #ifdef HAVE_NUMPY
00068 template <>
00069 PyArray_TYPES getEnum<unsigned long>(void)
00070 {
00071 return PyArray_ULONG;
00072 }
00073
00074 template <>
00075 PyArray_TYPES getEnum<long long>(void)
00076 {
00077 return PyArray_LONGLONG;
00078 }
00079
00080 template <>
00081 PyArray_TYPES getEnum<unsigned long long>(void)
00082 {
00083 return PyArray_ULONGLONG;
00084 }
00085 #endif
00086
00087 template <>
00088 PyArray_TYPES getEnum<float>(void)
00089 {
00090 return PyArray_FLOAT;
00091 }
00092
00093 template <>
00094 PyArray_TYPES getEnum<double>(void)
00095 {
00096 return PyArray_DOUBLE;
00097 }
00098
00099 #ifdef HAVE_NUMPY
00100 template <>
00101 PyArray_TYPES getEnum<long double>(void)
00102 {
00103 return PyArray_LONGDOUBLE;
00104 }
00105 #endif
00106 template <>
00107 PyArray_TYPES getEnum<std::complex<float> >(void)
00108 {
00109 return PyArray_CFLOAT;
00110 }
00111
00112
00113 template <>
00114 PyArray_TYPES getEnum<std::complex<double> >(void)
00115 {
00116 return PyArray_CDOUBLE;
00117 }
00118
00119 #ifdef HAVE_NUMPY
00120 template <>
00121 PyArray_TYPES getEnum<std::complex<long double> >(void)
00122 {
00123 return PyArray_CLONGDOUBLE;
00124 }
00125 #endif
00126
00127 template <> boost::python::numeric::array makeNum<double> (double * data, std::vector<int> dims){
00128 intp total = std::accumulate(dims.begin(),dims.end(),1,std::multiplies<intp>());
00129 boost::python::object obj(boost::python::handle<>(PyArray_FromDims(dims.size(),&dims[0], PyArray_DOUBLE)));
00130 #ifdef HAVE_NUMPY
00131 void *arr_data = PyArray_DATA((PyArrayObject*) obj.ptr());
00132 memcpy(arr_data, data, PyArray_ITEMSIZE((PyArrayObject*) obj.ptr()) * total);
00133 #else
00134 char *arr_data = ((PyArrayObject*) obj.ptr())->data;
00135 memcpy(arr_data, data, sizeof(double) * total);
00136
00137 #endif
00138 return boost::python::extract<boost::python::numeric::array>(obj);
00139 }
00140
00141
00142 typedef KindStringMap::value_type KindStringMapEntry;
00143 KindStringMapEntry kindStringMapEntries[] =
00144 {
00145 KindStringMapEntry(PyArray_UBYTE, "PyArray_UBYTE"),
00146 #ifdef HAVE_NUMPY
00147 KindStringMapEntry(PyArray_BYTE, "PyArray_BYTE"),
00148 #else
00149 KindStringMapEntry(PyArray_SBYTE, "PyArray_SBYTE"),
00150 #endif
00151 KindStringMapEntry(PyArray_SHORT, "PyArray_SHORT"),
00152 KindStringMapEntry(PyArray_INT, "PyArray_INT"),
00153 KindStringMapEntry(PyArray_LONG, "PyArray_LONG"),
00154 KindStringMapEntry(PyArray_FLOAT, "PyArray_FLOAT"),
00155 KindStringMapEntry(PyArray_DOUBLE, "PyArray_DOUBLE"),
00156 KindStringMapEntry(PyArray_CFLOAT, "PyArray_CFLOAT"),
00157 KindStringMapEntry(PyArray_CDOUBLE,"PyArray_CDOUBLE"),
00158 KindStringMapEntry(PyArray_OBJECT, "PyArray_OBJECT"),
00159 KindStringMapEntry(PyArray_NTYPES, "PyArray_NTYPES"),
00160 KindStringMapEntry(PyArray_NOTYPE ,"PyArray_NOTYPE")
00161 };
00162
00163 typedef KindCharMap::value_type KindCharMapEntry;
00164 KindCharMapEntry kindCharMapEntries[] =
00165 {
00166 KindCharMapEntry(PyArray_UBYTE, 'B'),
00167 #ifdef HAVE_NUMPY
00168 KindCharMapEntry(PyArray_BYTE, 'b'),
00169 #else
00170 KindCharMapEntry(PyArray_SBYTE, 'b'),
00171 #endif
00172 KindCharMapEntry(PyArray_SHORT, 'h'),
00173 KindCharMapEntry(PyArray_INT, 'i'),
00174 KindCharMapEntry(PyArray_LONG, 'l'),
00175 KindCharMapEntry(PyArray_FLOAT, 'f'),
00176 KindCharMapEntry(PyArray_DOUBLE, 'd'),
00177 KindCharMapEntry(PyArray_CFLOAT, 'F'),
00178 KindCharMapEntry(PyArray_CDOUBLE,'D'),
00179 KindCharMapEntry(PyArray_OBJECT, 'O')
00180 };
00181
00182 typedef KindTypeMap::value_type KindTypeMapEntry;
00183 KindTypeMapEntry kindTypeMapEntries[] =
00184 {
00185 KindTypeMapEntry('B',PyArray_UBYTE),
00186 #ifdef HAVE_NUMPY
00187 KindTypeMapEntry('b',PyArray_BYTE),
00188 #else
00189 KindTypeMapEntry('b',PyArray_SBYTE),
00190 #endif
00191 KindTypeMapEntry('h',PyArray_SHORT),
00192 KindTypeMapEntry('i',PyArray_INT),
00193 KindTypeMapEntry('l',PyArray_LONG),
00194 KindTypeMapEntry('f',PyArray_FLOAT),
00195 KindTypeMapEntry('d',PyArray_DOUBLE),
00196 KindTypeMapEntry('F',PyArray_CFLOAT),
00197 KindTypeMapEntry('D',PyArray_CDOUBLE),
00198 KindTypeMapEntry('O',PyArray_OBJECT)
00199 };
00200
00201
00202 int numStringEntries = sizeof(kindStringMapEntries)/sizeof(KindStringMapEntry);
00203 int numCharEntries = sizeof(kindCharMapEntries)/sizeof(KindCharMapEntry);
00204 int numTypeEntries = sizeof(kindTypeMapEntries)/sizeof(KindTypeMapEntry);
00205
00206
00207 using namespace boost::python;
00208
00209 static KindStringMap kindstrings(kindStringMapEntries,
00210 kindStringMapEntries + numStringEntries);
00211
00212 static KindCharMap kindchars(kindCharMapEntries,
00213 kindCharMapEntries + numCharEntries);
00214
00215 static KindTypeMap kindtypes(kindTypeMapEntries,
00216 kindTypeMapEntries + numTypeEntries);
00217
00218
00219 numeric::array makeNum(object x){
00220 if (!PySequence_Check(x.ptr())){
00221 PyErr_SetString(PyExc_ValueError, "expected a sequence");
00222 throw_error_already_set();
00223 }
00224 object obj(handle<>
00225 (PyArray_ContiguousFromObject(x.ptr(),PyArray_NOTYPE,0,0)));
00226 check_PyArrayElementType(obj);
00227 return extract<numeric::array>(obj);
00228 }
00229
00230
00231 numeric::array makeNum(int n, PyArray_TYPES t=PyArray_DOUBLE){
00232 object obj(handle<>(PyArray_FromDims(1, &n, t)));
00233 return extract<numeric::array>(obj);
00234 }
00235
00236
00237 numeric::array makeNum(std::vector<int> dimens,
00238 PyArray_TYPES t=PyArray_DOUBLE){
00239 object obj(handle<>(PyArray_FromDims(dimens.size(), &dimens[0], t)));
00240 return extract<numeric::array>(obj);
00241 }
00242
00243 numeric::array makeNum(const numeric::array& arr){
00244
00245
00246 return numeric::array(arr);
00247 }
00248
00249 PyArray_TYPES type(numeric::array arr){
00250 #ifdef HAVE_NUMPY
00251 return PyArray_TYPES(PyArray_TYPE(arr.ptr()));
00252 #else
00253 return char2type(arr.typecode());
00254 #endif
00255 }
00256
00257 void check_type(boost::python::numeric::array arr,
00258 PyArray_TYPES expected_type){
00259 PyArray_TYPES actual_type = type(arr);
00260 if (actual_type != expected_type) {
00261 std::ostringstream stream;
00262 stream << "expected Numeric type " << kindstrings[expected_type]
00263 << ", found Numeric type " << kindstrings[actual_type] << std::ends;
00264 PyErr_SetString(PyExc_TypeError, stream.str().c_str());
00265 throw_error_already_set();
00266 }
00267 return;
00268 }
00269
00270
00271 int rank(numeric::array arr){
00272
00273 if(!PyArray_Check(arr.ptr())){
00274 PyErr_SetString(PyExc_ValueError, "expected a PyArrayObject");
00275 throw_error_already_set();
00276 }
00277 #ifdef HAVE_NUMPY
00278 return PyArray_NDIM(arr.ptr());
00279 #else
00280 return ((PyArrayObject*) arr.ptr())->nd;
00281 #endif
00282 }
00283
00284 void check_rank(boost::python::numeric::array arr, int expected_rank){
00285 int actual_rank = rank(arr);
00286 if (actual_rank != expected_rank) {
00287 std::ostringstream stream;
00288 stream << "expected rank " << expected_rank
00289 << ", found rank " << actual_rank << std::ends;
00290 PyErr_SetString(PyExc_RuntimeError, stream.str().c_str());
00291 throw_error_already_set();
00292 }
00293 return;
00294 }
00295
00296 intp size(numeric::array arr)
00297 {
00298 if(!PyArray_Check(arr.ptr())){
00299 PyErr_SetString(PyExc_ValueError, "expected a PyArrayObject");
00300 throw_error_already_set();
00301 }
00302 return PyArray_Size(arr.ptr());
00303 }
00304
00305 void check_size(boost::python::numeric::array arr, intp expected_size){
00306 intp actual_size = size(arr);
00307 if (actual_size != expected_size) {
00308 std::ostringstream stream;
00309 stream << "expected size " << expected_size
00310 << ", found size " << actual_size << std::ends;
00311 PyErr_SetString(PyExc_RuntimeError, stream.str().c_str());
00312 throw_error_already_set();
00313 }
00314 return;
00315 }
00316
00317 std::vector<intptr_t> shape(numeric::array arr){
00318 std::vector<intptr_t> out_dims;
00319 if(!PyArray_Check(arr.ptr())){
00320 PyErr_SetString(PyExc_ValueError, "expected a PyArrayObject");
00321 throw_error_already_set();
00322 }
00323 #ifdef HAVE_NUMPY
00324 intp* dims_ptr = PyArray_DIMS(arr.ptr());
00325 #else
00326 int* dims_ptr = ((PyArrayObject*) arr.ptr())->dimensions;
00327 #endif
00328 int the_rank = rank(arr);
00329 for (int i = 0; i < the_rank; i++){
00330 out_dims.push_back(*(dims_ptr + i));
00331 }
00332 return out_dims;
00333 }
00334
00335 intp get_dim(boost::python::numeric::array arr, int dimnum){
00336 assert(dimnum >= 0);
00337 int the_rank=rank(arr);
00338 if(the_rank < dimnum){
00339 std::ostringstream stream;
00340 stream << "Error: asked for length of dimension ";
00341 stream << dimnum << " but rank of array is " << the_rank << std::ends;
00342 PyErr_SetString(PyExc_RuntimeError, stream.str().c_str());
00343 throw_error_already_set();
00344 }
00345 std::vector<intptr_t> actual_dims = shape(arr);
00346 return actual_dims[dimnum];
00347 }
00348
00349 void check_shape(boost::python::numeric::array arr, std::vector<intptr_t> expected_dims){
00350 std::vector<intptr_t> actual_dims = shape(arr);
00351 if (actual_dims != expected_dims) {
00352 std::ostringstream stream;
00353 stream << "expected dimensions " << vector_str(expected_dims)
00354 << ", found dimensions " << vector_str(actual_dims) << std::ends;
00355 PyErr_SetString(PyExc_RuntimeError, stream.str().c_str());
00356 throw_error_already_set();
00357 }
00358 return;
00359 }
00360
00361 void check_dim(boost::python::numeric::array arr, int dimnum, intp dimsize){
00362 std::vector<intptr_t> actual_dims = shape(arr);
00363 if(actual_dims[dimnum] != dimsize){
00364 std::ostringstream stream;
00365 stream << "Error: expected dimension number ";
00366 stream << dimnum << " to be length " << dimsize;
00367 stream << ", but found length " << actual_dims[dimnum] << std::ends;
00368 PyErr_SetString(PyExc_RuntimeError, stream.str().c_str());
00369 throw_error_already_set();
00370 }
00371 return;
00372 }
00373
00374 bool iscontiguous(numeric::array arr)
00375 {
00376
00377 return PyArray_ISCONTIGUOUS(arr.ptr());
00378 }
00379
00380 void check_contiguous(numeric::array arr)
00381 {
00382 if (!iscontiguous(arr)) {
00383 PyErr_SetString(PyExc_RuntimeError, "expected a contiguous array");
00384 throw_error_already_set();
00385 }
00386 return;
00387 }
00388
00389 void* data(numeric::array arr){
00390 if(!PyArray_Check(arr.ptr())){
00391 PyErr_SetString(PyExc_ValueError, "expected a PyArrayObject");
00392 throw_error_already_set();
00393 }
00394 #ifdef HAVE_NUMPY
00395 return PyArray_DATA(arr.ptr());
00396 #else
00397 return ((PyArrayObject*) arr.ptr())->data;
00398 #endif
00399 }
00400
00401
00402 void copy_data(boost::python::numeric::array arr, char* new_data){
00403 char* arr_data = (char*) data(arr);
00404 intp nbytes = PyArray_NBYTES(arr.ptr());
00405 for (intp i = 0; i < nbytes; i++) {
00406 arr_data[i] = new_data[i];
00407 }
00408 return;
00409 }
00410
00411
00412 numeric::array clone(numeric::array arr){
00413 #ifdef HAVE_NUMPY
00414 object obj(handle<>(PyArray_NewCopy((PyArrayObject*)arr.ptr(),PyArray_CORDER)));
00415 #else
00416 object obj(handle<>(PyArray_Copy((PyArrayObject*)arr.ptr())));
00417 #endif
00418 return makeNum(obj);
00419 }
00420
00421
00422
00423 numeric::array astype(boost::python::numeric::array arr, PyArray_TYPES t){
00424 return (numeric::array) arr.astype(type2char(t));
00425 }
00426
00427 std::vector<intp> strides(numeric::array arr){
00428 std::vector<intp> out_strides;
00429 if(!PyArray_Check(arr.ptr())){
00430 PyErr_SetString(PyExc_ValueError, "expected a PyArrayObject");
00431 throw_error_already_set();
00432 }
00433 #ifdef HAVE_NUMPY
00434 intp* strides_ptr = PyArray_STRIDES(arr.ptr());
00435 #else
00436 int* strides_ptr = ((PyArrayObject*) arr.ptr())->strides;
00437 #endif
00438 intp the_rank = rank(arr);
00439 for (intp i = 0; i < the_rank; i++){
00440 out_strides.push_back(*(strides_ptr + i));
00441 }
00442 return out_strides;
00443 }
00444
00445 int refcount(numeric::array arr){
00446 return REFCOUNT(arr.ptr());
00447 }
00448
00449 void check_PyArrayElementType(object newo){
00450 #ifdef HAVE_NUMPY
00451 PyArray_TYPES theType=PyArray_TYPES(PyArray_TYPE(newo.ptr()));
00452 #else
00453 PyArrayObject* PyArrayPtr = (PyArrayObject*) newo.ptr();
00454 PyArray_TYPES theType=(PyArray_TYPES) PyArrayPtr->descr->type_num;
00455 #endif
00456 if(theType == PyArray_OBJECT){
00457 std::ostringstream stream;
00458 stream << "array elments have been cast to PyArray_OBJECT, "
00459 << "numhandle can only accept arrays with numerical elements"
00460 << std::ends;
00461 PyErr_SetString(PyExc_TypeError, stream.str().c_str());
00462 throw_error_already_set();
00463 }
00464 return;
00465 }
00466
00467 std::string type2string(PyArray_TYPES t_type){
00468 return kindstrings[t_type];
00469 }
00470
00471 char type2char(PyArray_TYPES t_type){
00472 return kindchars[t_type];
00473 }
00474
00475 PyArray_TYPES char2type(char e_type){
00476 return kindtypes[e_type];
00477 }
00478
00479 template <class T>
00480 inline std::string vector_str(const std::vector<T>& vec)
00481 {
00482 std::ostringstream stream;
00483 stream << "(" << vec[0];
00484
00485 for(std::size_t i = 1; i < vec.size(); i++){
00486 stream << ", " << vec[i];
00487 }
00488 stream << ")";
00489 return stream.str();
00490 }
00491
00492 inline void check_size_match(std::vector<intp> dims, intp n)
00493 {
00494 intp total = std::accumulate(dims.begin(),dims.end(),1,std::multiplies<intp>());
00495 if (total != n) {
00496 std::ostringstream stream;
00497 stream << "expected array size " << n
00498 << ", dimensions give array size " << total << std::ends;
00499 PyErr_SetString(PyExc_TypeError, stream.str().c_str());
00500 throw_error_already_set();
00501 }
00502 return;
00503 }
00504
00505 }
00506