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