[C++-sig] Re: regarding your post entitled " Numeric--factory function" onBoost.Python

Faheem Mitha faheem at email.unc.edu
Wed Nov 3 02:29:19 CET 2004


Hi Li,

Thanks for your helpful reply. Sorry you had difficulties posting to my 
address. If you continue to have problems, please let me know and I will 
report it.

On Mon, 1 Nov 2004, Li Dongfeng wrote:

> Hi Faheem,
>
>>   boost::python::numeric::array arr(dim1,dim2);
> --------------------------------------^^^^^^^^^
> The problem with you code is the array constructor function usage.
> That function cannot be called with two integers. See the numarray
> (or Numeric) docs for correct usage.

Well, it was not intended to be working code, just an example of what I 
had in mind.

>   I tested some solution but cannot reach an elegant one.
> An elegant solution should use the numarray(or Numeric) API
> directly to access the array contents in C++.
> But I have only got a make-shift solution: use the boost::python
> indexing suite. After you have used the indexing suite to map C++ vector
> to Python sequence type, you can use a C++ vector as a python sequence
> in C++ to initialize a numarray.array.
>
>  To map a C++ std::vector<double> to a Python sequence type named
> ``DoubleVec'', just make this boost.python extension:
>
> ------------------------
> #include <boost/python/suite/indexing/vector_indexing_suite.hpp>
> #include <boost/python/implicit.hpp>
> #include <boost/python/numeric.hpp>
> #include <boost/python/tuple.hpp>
> #include <boost/python/module.hpp>
> #include <boost/python/def.hpp>
> #include <vector>
> BOOST_PYTHON_MODULE(_numpyext)
> {
>  class_<std::vector<double> >("DoubleVec")
>    .def(vector_indexing_suite<std::vector<double> >());
> }
> ---------------
>
> Then in a C++ extension module, use:
>
> ---------------
> // std::vector conversion to numarray.array
> numeric::array vec2array_double(std::vector<double> x){
>  return numeric::array(x, "Float64");
> }
> BOOST_PYTHON_MODULE(_numpyext)
> {
>  def("_cppvec2array", &vec2array_double);
> }
> ---------------
>
> this really works, the ``x'' in the numeric::array function call
> is recognized by the numarray module constructor function ``array''
> as a python sequence of type ``DoubleVec''.

I don't see why, if the second argument is supposed to be a list, why you 
can't just create a Boost::python::list in C++, and then pass it in as a 
argument. Isn't that equivalent? Eg.

  //Convert (C++) numeric matrix to (Python) Numarray numeric array.
  boost::python::object cppmat2pynumarr(Array2D<double> A)
  {
    int i, j;
    int dim1 = A.dim1();
    int dim2 = A.dim2();

    boost::python::list lst;

    for(i=0; i<dim1; i++)
      for(j=0; j<dim2; j++)
        lst.append(A[i][j]);

    return boost::python::numeric::array(lst,"Double", make_tuple(dim1,
  								dim2));

  }

This compiles without problems. However, this does not work. I get errors 
like this:

************************************************************************
Traceback (most recent call last):
   File "test.py", line 8, in ?
     concatfoobar = genepath.cpp_concatmat(foo,bar)
   File "/usr/lib/python2.3/site-packages/numarray/numarraycore.py", line 
321, in array
     type = getTypeObject(sequence, type, typecode)
   File "/usr/lib/python2.3/site-packages/numarray/numarraycore.py", line 
256, in getTypeObject
     rtype = _typeFromTypeAndTypecode(type, typecode)
   File "/usr/lib/python2.3/site-packages/numarray/numarraycore.py", line 
247, in _typeFromTypeAndTypecode
     return _nt.getType(typecode)
   File "/usr/lib/python2.3/site-packages/numarray/numerictypes.py", line 
462, in getType
     raise TypeError("Not a numeric type")
TypeError: Not a numeric type
************************************************************************

The method you suggested does work as you described it, though I am not 
clear why the above does not work, and what you suggest does. Ie

*************************************************************************
//Convert (C++) numeric matrix to (Python) Numarray numeric array.
boost::python::object cppmat2pynumarr(Array2D<double> A)
{
   int i, j;
   int dim1 = A.dim1();
   int dim2 = A.dim2();

   vector<double> vec;

   for(i=0; i<dim1; i++)
     for(j=0; j<dim2; j++)
       vec.push_back(A[i][j]);

   return  vec2array_double(vec);
}
*************************************************************************

where vec2array_double is as you defined it.

This gives

***********************************************************************
In [3]: foo
Out[3]:
array([[1, 2],
        [3, 4]])

In [4]: bar
Out[4]:
array([[0, 0],
        [0, 0]])

In [5]: concatfoobar
Out[5]: array([ 1.,  2.,  3.,  4.,  0.,  0.,  0.,  0.])
************************************************************************

However, this is not completely satisfactory. I would prefer to set the 
shape in the C++ code itself. Why is this not possible? Why is it 
necessary to do so in Python code? I don't want a Python wrapper for my 
C++ code.

I tried something like

******************************************************************
// std::vector conversion to numarray.array
boost::python::numeric::array vec2array_double(std::vector<double> x)
{
   boost::python::tuple foo = make_tuple(2,2);
   return boost::python::numeric::array(x, "Float64", foo);
}
*****************************************************************

This compiles without complaint, but does not reshape the array.

Furthermore, I am unclear on a fundamental point.

What *is* the constructor of the Numeric array in C++? From the 
documentation at http://www.boost.org/libs/python/doc/v2/numeric.html I 
thought that these were C++ functions called factory.

The documentation says

"These functions map to the underlying array type's array()  function 
family. They are not called "array" because of the C++ limitation that you 
can't define a member function with the same name as its enclosing class."

I'm not sure what this means. How are you supposed to call them? Does
numeric::array call these functions? I could not find any relevant 
examples. There are examples in the examples directory in numpy.cc, but
I am not sure what to make of

************************************************************************
object new_array()
{
     return numeric::array(
         make_tuple(
             make_tuple(1,2,3)
           , make_tuple(4,5,6)
           , make_tuple(7,8,9)
             )
         );
}
*************************************************************************

This works, but how do I generalise it to do what I want, and which 
constructor does this belong to?

and

*************************************************************************

void exercise_numarray(numeric::array& y, object check)
{
...
check(y.factory(make_tuple(1.2, 3.4), "Double", make_tuple(1,2,1)));
...
*************************************************************************

What is that y doing, if this is a constructor? Looks more like a member 
function. I've tried variations on this too, but get errors at runtime.

So you can see I am quite confused. Thanks again.

                                                                Faheem.



More information about the Cplusplus-sig mailing list