1Ufuncs 2====== 3 4Ufuncs or universal functions operate on ndarrays element by element, and support array broadcasting, type casting, and other features. 5 6Lets try and see how we can use the binary and unary ufunc methods 7 8After the neccessary includes :: 9 10 #include <boost/python/numpy.hpp> 11 #include <iostream> 12 13 namespace p = boost::python; 14 namespace np = boost::python::numpy; 15 16Now 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 :: 17 18 struct UnarySquare 19 { 20 typedef double argument_type; 21 typedef double result_type; 22 23 double operator()(double r) const { return r * r;} 24 }; 25 26 struct BinarySquare 27 { 28 typedef double first_argument_type; 29 typedef double second_argument_type; 30 typedef double result_type; 31 32 double operator()(double a,double b) const { return (a*a + b*b) ; } 33 }; 34 35Initialise the Python runtime and the numpy module :: 36 37 int main(int argc, char **argv) 38 { 39 Py_Initialize(); 40 np::initialize(); 41 42Now expose the struct UnarySquare to Python as a class, and let ud be the class object. :: 43 44 p::object ud = p::class_<UnarySquare, boost::shared_ptr<UnarySquare> >("UnarySquare"); 45 ud.def("__call__", np::unary_ufunc<UnarySquare>::make()); 46 47Let inst be an instance of the class ud :: 48 49 p::object inst = ud(); 50 51Use the "__call__" method to call the overloaded () operator and print the value :: 52 53 std::cout << "Square of unary scalar 1.0 is " << p::extract<char const *>(p::str(inst.attr("__call__")(1.0))) << std::endl; 54 55Create an array in C++ :: 56 57 int arr[] = {1,2,3,4} ; 58 59 60..and use it to create the ndarray in Python :: 61 62 np::ndarray demo_array = np::from_data(arr, np::dtype::get_builtin<int>(), 63 p::make_tuple(4), 64 p::make_tuple(4), 65 p::object()); 66 67Print out the demo array :: 68 69 std::cout << "Demo array is " << p::extract<char const *>(p::str(demo_array)) << std::endl; 70 71Call the "__call__" method to perform the operation and assign the value to result_array :: 72 73 p::object result_array = inst.attr("__call__")(demo_array); 74 75Print the resultant array :: 76 77 std::cout << "Square of demo array is " << p::extract<char const *>(p::str(result_array)) << std::endl; 78 79Lets try the same with a list :: 80 81 p::list li; 82 li.append(3); 83 li.append(7); 84 85Print out the demo list :: 86 87 std::cout << "Demo list is " << p::extract<char const *>(p::str(li)) << std::endl; 88 89Call the ufunc for the list :: 90 91 result_array = inst.attr("__call__")(li); 92 93And print the list out :: 94 95 std::cout << "Square of demo list is " << p::extract<char const *>(p::str(result_array)) << std::endl; 96 97Now lets try Binary ufuncs. Again, expose the struct BinarySquare to Python as a class, and let ud be the class object :: 98 99 ud = p::class_<BinarySquare, boost::shared_ptr<BinarySquare> >("BinarySquare"); 100 ud.def("__call__", np::binary_ufunc<BinarySquare>::make()); 101 102And initialise ud :: 103 104 inst = ud(); 105 106Print the two input lists :: 107 108 std::cout << "The two input list for binary ufunc are " << std::endl 109 << p::extract<char const *>(p::str(demo_array)) << std::endl 110 << p::extract<char const *>(p::str(demo_array)) << std::endl; 111 112Call the binary ufunc taking demo_array as both inputs :: 113 114 result_array = inst.attr("__call__")(demo_array,demo_array); 115 116And print the output :: 117 118 std::cout << "Square of list with binary ufunc is " << p::extract<char const *>(p::str(result_array)) << std::endl; 119 } 120 121