Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

num_util.cpp

Go to the documentation of this file.
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 // For Windows    KindStringMapEntry(PyArray_NTYPES, "PyArray_NTYPES"),
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 //Create a numarray referencing Python sequence object
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 //Create a one-dimensional Numeric array of length n and Numeric type t
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 //Create a Numeric array with dimensions dimens and Numeric type t
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); // copies the input data to 
00105                                            // PyArrayObject->data
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   //Returns a reference of arr by calling numeric::array copy constructor.
00190   //The copy constructor increases arr's reference count.
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 //Return the number of dimensions
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   //  return arr.iscontiguous();
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 //Copy data into the array
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 //Return a clone of this array
00340 numeric::array clone(numeric::array arr){
00341   object obj(handle<>(PyArray_Copy((PyArrayObject*)arr.ptr())));
00342   return makeNum(obj);
00343 }
00344 
00345   
00346 //Return a clone of this array with a new type
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 } //namespace numarray_bpl

Generated for HippoDraw-1.14.8.5 by doxygen 1.4.3