[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