123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- Ufuncs
- ======
- Ufuncs or universal functions operate on ndarrays element by element, and support array broadcasting, type casting, and other features.
- Lets try and see how we can use the binary and unary ufunc methods
- After the neccessary includes ::
- #include <boost/python/numpy.hpp>
- #include <iostream>
-
- namespace p = boost::python;
- namespace np = boost::python::numpy;
- Now we create the structs necessary to implement the ufuncs. The typedefs *must* be made as the ufunc generators take these typedefs as inputs and return an error otherwise ::
- struct UnarySquare
- {
- typedef double argument_type;
- typedef double result_type;
-
- double operator()(double r) const { return r * r;}
- };
-
- struct BinarySquare
- {
- typedef double first_argument_type;
- typedef double second_argument_type;
- typedef double result_type;
-
- double operator()(double a,double b) const { return (a*a + b*b) ; }
- };
- Initialise the Python runtime and the numpy module ::
- int main(int argc, char **argv)
- {
- Py_Initialize();
- np::initialize();
- Now expose the struct UnarySquare to Python as a class, and let ud be the class object. ::
- p::object ud = p::class_<UnarySquare, boost::shared_ptr<UnarySquare> >("UnarySquare");
- ud.def("__call__", np::unary_ufunc<UnarySquare>::make());
- Let inst be an instance of the class ud ::
- p::object inst = ud();
- Use the "__call__" method to call the overloaded () operator and print the value ::
- std::cout << "Square of unary scalar 1.0 is " << p::extract<char const *>(p::str(inst.attr("__call__")(1.0))) << std::endl;
- Create an array in C++ ::
- int arr[] = {1,2,3,4} ;
- ..and use it to create the ndarray in Python ::
- np::ndarray demo_array = np::from_data(arr, np::dtype::get_builtin<int>(),
- p::make_tuple(4),
- p::make_tuple(4),
- p::object());
- Print out the demo array ::
- std::cout << "Demo array is " << p::extract<char const *>(p::str(demo_array)) << std::endl;
- Call the "__call__" method to perform the operation and assign the value to result_array ::
- p::object result_array = inst.attr("__call__")(demo_array);
- Print the resultant array ::
-
- std::cout << "Square of demo array is " << p::extract<char const *>(p::str(result_array)) << std::endl;
- Lets try the same with a list ::
- p::list li;
- li.append(3);
- li.append(7);
- Print out the demo list ::
- std::cout << "Demo list is " << p::extract<char const *>(p::str(li)) << std::endl;
- Call the ufunc for the list ::
- result_array = inst.attr("__call__")(li);
- And print the list out ::
- std::cout << "Square of demo list is " << p::extract<char const *>(p::str(result_array)) << std::endl;
- Now lets try Binary ufuncs. Again, expose the struct BinarySquare to Python as a class, and let ud be the class object ::
- ud = p::class_<BinarySquare, boost::shared_ptr<BinarySquare> >("BinarySquare");
- ud.def("__call__", np::binary_ufunc<BinarySquare>::make());
- And initialise ud ::
- inst = ud();
- Print the two input lists ::
- std::cout << "The two input list for binary ufunc are " << std::endl
- << p::extract<char const *>(p::str(demo_array)) << std::endl
- << p::extract<char const *>(p::str(demo_array)) << std::endl;
- Call the binary ufunc taking demo_array as both inputs ::
- result_array = inst.attr("__call__")(demo_array,demo_array);
- And print the output ::
- std::cout << "Square of list with binary ufunc is " << p::extract<char const *>(p::str(result_array)) << std::endl;
- }
-
|