summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/python/test/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/python/test/numpy')
-rw-r--r--src/boost/libs/python/test/numpy/dtype.cpp49
-rw-r--r--src/boost/libs/python/test/numpy/dtype.py63
-rw-r--r--src/boost/libs/python/test/numpy/indexing.cpp28
-rw-r--r--src/boost/libs/python/test/numpy/indexing.py55
-rw-r--r--src/boost/libs/python/test/numpy/ndarray.cpp51
-rw-r--r--src/boost/libs/python/test/numpy/ndarray.py112
-rw-r--r--src/boost/libs/python/test/numpy/shapes.cpp22
-rw-r--r--src/boost/libs/python/test/numpy/shapes.py21
-rw-r--r--src/boost/libs/python/test/numpy/templates.cpp63
-rwxr-xr-xsrc/boost/libs/python/test/numpy/templates.py28
-rw-r--r--src/boost/libs/python/test/numpy/ufunc.cpp36
-rwxr-xr-xsrc/boost/libs/python/test/numpy/ufunc.py57
12 files changed, 585 insertions, 0 deletions
diff --git a/src/boost/libs/python/test/numpy/dtype.cpp b/src/boost/libs/python/test/numpy/dtype.cpp
new file mode 100644
index 000000000..3a011a25e
--- /dev/null
+++ b/src/boost/libs/python/test/numpy/dtype.cpp
@@ -0,0 +1,49 @@
+// Copyright Jim Bosch & Ankit Daftery 2010-2012.
+// Copyright Stefan Seefeld 2016.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/python/numpy.hpp>
+#include <boost/cstdint.hpp>
+
+namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+template <typename T>
+np::dtype accept(T) {
+ return np::dtype::get_builtin<T>();
+}
+
+BOOST_PYTHON_MODULE(dtype_ext)
+{
+ np::initialize();
+ // wrap dtype equivalence test, since it isn't available in Python API.
+ p::def("equivalent", np::equivalent);
+ // integers, by number of bits
+ p::def("accept_int8", accept<boost::int8_t>);
+ p::def("accept_uint8", accept<boost::uint8_t>);
+ p::def("accept_int16", accept<boost::int16_t>);
+ p::def("accept_uint16", accept<boost::uint16_t>);
+ p::def("accept_int32", accept<boost::int32_t>);
+ p::def("accept_uint32", accept<boost::uint32_t>);
+ p::def("accept_int64", accept<boost::int64_t>);
+ p::def("accept_uint64", accept<boost::uint64_t>);
+ // integers, by C name according to NumPy
+ p::def("accept_bool_", accept<bool>);
+ p::def("accept_byte", accept<signed char>);
+ p::def("accept_ubyte", accept<unsigned char>);
+ p::def("accept_short", accept<short>);
+ p::def("accept_ushort", accept<unsigned short>);
+ p::def("accept_intc", accept<int>);
+ p::def("accept_uintc", accept<unsigned int>);
+ // floats and complex
+ p::def("accept_float32", accept<float>);
+ p::def("accept_complex64", accept< std::complex<float> >);
+ p::def("accept_float64", accept<double>);
+ p::def("accept_complex128", accept< std::complex<double> >);
+ if (sizeof(long double) > sizeof(double)) {
+ p::def("accept_longdouble", accept<long double>);
+ p::def("accept_clongdouble", accept< std::complex<long double> >);
+ }
+}
diff --git a/src/boost/libs/python/test/numpy/dtype.py b/src/boost/libs/python/test/numpy/dtype.py
new file mode 100644
index 000000000..a27ee0f55
--- /dev/null
+++ b/src/boost/libs/python/test/numpy/dtype.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+
+# Copyright Jim Bosch & Ankit Daftery 2010-2012.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+import dtype_ext
+import unittest
+import numpy
+import sys
+if (sys.version_info.major >= 3):
+ long = int
+
+class DtypeTestCase(unittest.TestCase):
+
+ def assertEquivalent(self, a, b):
+ return self.assert_(dtype_ext.equivalent(a, b), "%r is not equivalent to %r")
+
+ def testIntegers(self):
+ for bits in (8, 16, 32, 64):
+ s = getattr(numpy, "int%d" % bits)
+ u = getattr(numpy, "uint%d" % bits)
+ fs = getattr(dtype_ext, "accept_int%d" % bits)
+ fu = getattr(dtype_ext, "accept_uint%d" % bits)
+ self.assertEquivalent(fs(s(1)), numpy.dtype(s))
+ self.assertEquivalent(fu(u(1)), numpy.dtype(u))
+ # these should just use the regular Boost.Python converters
+ self.assertEquivalent(fs(True), numpy.dtype(s))
+ self.assertEquivalent(fu(True), numpy.dtype(u))
+ self.assertEquivalent(fs(int(1)), numpy.dtype(s))
+ self.assertEquivalent(fu(int(1)), numpy.dtype(u))
+ self.assertEquivalent(fs(long(1)), numpy.dtype(s))
+ self.assertEquivalent(fu(long(1)), numpy.dtype(u))
+ for name in ("bool_", "byte", "ubyte", "short", "ushort", "intc", "uintc"):
+ t = getattr(numpy, name)
+ ft = getattr(dtype_ext, "accept_%s" % name)
+ self.assertEquivalent(ft(t(1)), numpy.dtype(t))
+ # these should just use the regular Boost.Python converters
+ self.assertEquivalent(ft(True), numpy.dtype(t))
+ if name != "bool_":
+ self.assertEquivalent(ft(int(1)), numpy.dtype(t))
+ self.assertEquivalent(ft(long(1)), numpy.dtype(t))
+
+
+ def testFloats(self):
+ f = numpy.float32
+ c = numpy.complex64
+ self.assertEquivalent(dtype_ext.accept_float32(f(numpy.pi)), numpy.dtype(f))
+ self.assertEquivalent(dtype_ext.accept_complex64(c(1+2j)), numpy.dtype(c))
+ f = numpy.float64
+ c = numpy.complex128
+ self.assertEquivalent(dtype_ext.accept_float64(f(numpy.pi)), numpy.dtype(f))
+ self.assertEquivalent(dtype_ext.accept_complex128(c(1+2j)), numpy.dtype(c))
+ if hasattr(numpy, "longdouble") and hasattr(dtype_ext, "accept_longdouble"):
+ f = numpy.longdouble
+ c = numpy.clongdouble
+ self.assertEquivalent(dtype_ext.accept_longdouble(f(numpy.pi)), numpy.dtype(f))
+ self.assertEquivalent(dtype_ext.accept_clongdouble(c(1+2j)), numpy.dtype(c))
+
+
+if __name__=="__main__":
+ unittest.main()
diff --git a/src/boost/libs/python/test/numpy/indexing.cpp b/src/boost/libs/python/test/numpy/indexing.cpp
new file mode 100644
index 000000000..f3cc45717
--- /dev/null
+++ b/src/boost/libs/python/test/numpy/indexing.cpp
@@ -0,0 +1,28 @@
+// Copyright Jim Bosch & Ankit Daftery 2010-2012.
+// Copyright Stefan Seefeld 2016.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/python/numpy.hpp>
+#include <boost/python/slice.hpp>
+
+namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+p::object single(np::ndarray ndarr, int i) { return ndarr[i];}
+p::object slice(np::ndarray ndarr, p::slice sl) { return ndarr[sl];}
+p::object indexarray(np::ndarray ndarr, np::ndarray d1) { return ndarr[d1];}
+p::object indexarray_2d(np::ndarray ndarr, np::ndarray d1,np::ndarray d2) { return ndarr[p::make_tuple(d1,d2)];}
+p::object indexslice(np::ndarray ndarr, np::ndarray d1, p::slice sl) { return ndarr[p::make_tuple(d1, sl)];}
+
+BOOST_PYTHON_MODULE(indexing_ext)
+{
+ np::initialize();
+ p::def("single", single);
+ p::def("slice", slice);
+ p::def("indexarray", indexarray);
+ p::def("indexarray", indexarray_2d);
+ p::def("indexslice", indexslice);
+
+}
diff --git a/src/boost/libs/python/test/numpy/indexing.py b/src/boost/libs/python/test/numpy/indexing.py
new file mode 100644
index 000000000..ebd9dcbab
--- /dev/null
+++ b/src/boost/libs/python/test/numpy/indexing.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+# Copyright Jim Bosch & Ankit Daftery 2010-2012.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+import unittest
+import numpy
+import indexing_ext
+
+class TestIndexing(unittest.TestCase):
+
+ def testSingle(self):
+ x = numpy.arange(0,10)
+ for i in range(0,10):
+ numpy.testing.assert_equal(indexing_ext.single(x,i), i)
+ for i in range(-10,0):
+ numpy.testing.assert_equal(indexing_ext.single(x,i),10+i)
+
+ def testSlice(self):
+ x = numpy.arange(0,10)
+ sl = slice(3,8)
+ b = [3,4,5,6,7]
+ numpy.testing.assert_equal(indexing_ext.slice(x,sl), b)
+
+ def testStepSlice(self):
+ x = numpy.arange(0,10)
+ sl = slice(3,8,2)
+ b = [3,5,7]
+ numpy.testing.assert_equal(indexing_ext.slice(x,sl), b)
+
+ def testIndex(self):
+ x = numpy.arange(0,10)
+ chk = numpy.array([3,4,5,6])
+ numpy.testing.assert_equal(indexing_ext.indexarray(x,chk),chk)
+ chk = numpy.array([[0,1],[2,3]])
+ numpy.testing.assert_equal(indexing_ext.indexarray(x,chk),chk)
+ x = numpy.arange(9).reshape(3,3)
+ y = numpy.array([0,1])
+ z = numpy.array([0,2])
+ chk = numpy.array([0,5])
+ numpy.testing.assert_equal(indexing_ext.indexarray(x,y,z),chk)
+ x = numpy.arange(0,10)
+ b = x>4
+ chk = numpy.array([5,6,7,8,9])
+ numpy.testing.assert_equal(indexing_ext.indexarray(x,b),chk)
+ x = numpy.arange(9).reshape(3,3)
+ b = numpy.array([0,2])
+ sl = slice(0,3)
+ chk = numpy.array([[0,1,2],[6,7,8]])
+ numpy.testing.assert_equal(indexing_ext.indexslice(x,b,sl),chk)
+
+if __name__=="__main__":
+ unittest.main()
diff --git a/src/boost/libs/python/test/numpy/ndarray.cpp b/src/boost/libs/python/test/numpy/ndarray.cpp
new file mode 100644
index 000000000..75a101043
--- /dev/null
+++ b/src/boost/libs/python/test/numpy/ndarray.cpp
@@ -0,0 +1,51 @@
+// Copyright Jim Bosch & Ankit Daftery 2010-2012.
+// Copyright Stefan Seefeld 2016.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/python/numpy.hpp>
+
+namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+np::ndarray zeros(p::tuple shape, np::dtype dt) { return np::zeros(shape, dt);}
+np::ndarray array2(p::object obj, np::dtype dt) { return np::array(obj,dt);}
+np::ndarray array1(p::object obj) { return np::array(obj);}
+np::ndarray empty1(p::tuple shape, np::dtype dt) { return np::empty(shape,dt);}
+
+np::ndarray c_empty(p::tuple shape, np::dtype dt)
+{
+ // convert 'shape' to a C array so we can test the corresponding
+ // version of the constructor
+ unsigned len = p::len(shape);
+ Py_intptr_t *c_shape = new Py_intptr_t[len];
+ for (unsigned i = 0; i != len; ++i)
+ c_shape[i] = p::extract<Py_intptr_t>(shape[i]);
+ np::ndarray result = np::empty(len, c_shape, dt);
+ delete [] c_shape;
+ return result;
+}
+
+np::ndarray transpose(np::ndarray arr) { return arr.transpose();}
+np::ndarray squeeze(np::ndarray arr) { return arr.squeeze();}
+np::ndarray reshape(np::ndarray arr,p::tuple tup) { return arr.reshape(tup);}
+
+Py_intptr_t shape_index(np::ndarray arr,int k) { return arr.shape(k); }
+Py_intptr_t strides_index(np::ndarray arr,int k) { return arr.strides(k); }
+
+BOOST_PYTHON_MODULE(ndarray_ext)
+{
+ np::initialize();
+ p::def("zeros", zeros);
+ p::def("zeros_matrix", zeros, np::as_matrix<>());
+ p::def("array", array2);
+ p::def("array", array1);
+ p::def("empty", empty1);
+ p::def("c_empty", c_empty);
+ p::def("transpose", transpose);
+ p::def("squeeze", squeeze);
+ p::def("reshape", reshape);
+ p::def("shape_index", shape_index);
+ p::def("strides_index", strides_index);
+}
diff --git a/src/boost/libs/python/test/numpy/ndarray.py b/src/boost/libs/python/test/numpy/ndarray.py
new file mode 100644
index 000000000..2acc384a5
--- /dev/null
+++ b/src/boost/libs/python/test/numpy/ndarray.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python
+
+# Copyright Jim Bosch & Ankit Daftery 2010-2012.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+import ndarray_ext
+import unittest
+import numpy
+
+class TestNdarray(unittest.TestCase):
+
+ def testNdzeros(self):
+ for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128):
+ v = numpy.zeros(60, dtype=dtp)
+ dt = numpy.dtype(dtp)
+ for shape in ((60,),(6,10),(4,3,5),(2,2,3,5)):
+ a1 = ndarray_ext.zeros(shape,dt)
+ a2 = v.reshape(a1.shape)
+ self.assertEqual(shape,a1.shape)
+ self.assert_((a1 == a2).all())
+
+ def testNdzeros_matrix(self):
+ for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128):
+ dt = numpy.dtype(dtp)
+ shape = (6, 10)
+ a1 = ndarray_ext.zeros_matrix(shape, dt)
+ a2 = numpy.matrix(numpy.zeros(shape, dtype=dtp))
+ self.assertEqual(shape,a1.shape)
+ self.assert_((a1 == a2).all())
+ self.assertEqual(type(a1), type(a2))
+
+ def testNdarray(self):
+ a = range(0,60)
+ for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128):
+ v = numpy.array(a, dtype=dtp)
+ dt = numpy.dtype(dtp)
+ a1 = ndarray_ext.array(a)
+ a2 = ndarray_ext.array(a,dt)
+ self.assert_((a1 == v).all())
+ self.assert_((a2 == v).all())
+ for shape in ((60,),(6,10),(4,3,5),(2,2,3,5)):
+ a1 = a1.reshape(shape)
+ self.assertEqual(shape,a1.shape)
+ a2 = a2.reshape(shape)
+ self.assertEqual(shape,a2.shape)
+
+ def testNdempty(self):
+ for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128):
+ dt = numpy.dtype(dtp)
+ for shape in ((60,),(6,10),(4,3,5),(2,2,3,5)):
+ a1 = ndarray_ext.empty(shape,dt)
+ a2 = ndarray_ext.c_empty(shape,dt)
+ self.assertEqual(shape,a1.shape)
+ self.assertEqual(shape,a2.shape)
+
+ def testTranspose(self):
+ for dtp in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128):
+ dt = numpy.dtype(dtp)
+ for shape in ((6,10),(4,3,5),(2,2,3,5)):
+ a1 = numpy.empty(shape,dt)
+ a2 = a1.transpose()
+ a1 = ndarray_ext.transpose(a1)
+ self.assertEqual(a1.shape,a2.shape)
+
+ def testSqueeze(self):
+ a1 = numpy.array([[[3,4,5]]])
+ a2 = a1.squeeze()
+ a1 = ndarray_ext.squeeze(a1)
+ self.assertEqual(a1.shape,a2.shape)
+
+ def testReshape(self):
+ a1 = numpy.empty((2,2))
+ a2 = ndarray_ext.reshape(a1,(1,4))
+ self.assertEqual(a2.shape,(1,4))
+
+ def testShapeIndex(self):
+ a = numpy.arange(24)
+ a.shape = (1,2,3,4)
+ def shape_check(i):
+ print(i)
+ self.assertEqual(ndarray_ext.shape_index(a,i) ,a.shape[i] )
+ for i in range(4):
+ shape_check(i)
+ for i in range(-1,-5,-1):
+ shape_check(i)
+ try:
+ ndarray_ext.shape_index(a,4) # out of bounds -- should raise IndexError
+ self.assertTrue(False)
+ except IndexError:
+ pass
+
+ def testStridesIndex(self):
+ a = numpy.arange(24)
+ a.shape = (1,2,3,4)
+ def strides_check(i):
+ print(i)
+ self.assertEqual(ndarray_ext.strides_index(a,i) ,a.strides[i] )
+ for i in range(4):
+ strides_check(i)
+ for i in range(-1,-5,-1):
+ strides_check(i)
+ try:
+ ndarray_ext.strides_index(a,4) # out of bounds -- should raise IndexError
+ self.assertTrue(False)
+ except IndexError:
+ pass
+
+
+if __name__=="__main__":
+ unittest.main()
diff --git a/src/boost/libs/python/test/numpy/shapes.cpp b/src/boost/libs/python/test/numpy/shapes.cpp
new file mode 100644
index 000000000..a245df155
--- /dev/null
+++ b/src/boost/libs/python/test/numpy/shapes.cpp
@@ -0,0 +1,22 @@
+// Copyright Jim Bosch & Ankit Daftery 2010-2012.
+// Copyright Stefan Seefeld 2016.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/python/numpy.hpp>
+
+namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+np::ndarray reshape(np::ndarray old_array, p::tuple shape)
+{
+ np::ndarray local_shape = old_array.reshape(shape);
+ return local_shape;
+}
+
+BOOST_PYTHON_MODULE(shapes_ext)
+{
+ np::initialize();
+ p::def("reshape", reshape);
+}
diff --git a/src/boost/libs/python/test/numpy/shapes.py b/src/boost/libs/python/test/numpy/shapes.py
new file mode 100644
index 000000000..d0a0099ca
--- /dev/null
+++ b/src/boost/libs/python/test/numpy/shapes.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright Jim Bosch & Ankit Daftery 2010-2012.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+import shapes_ext
+import unittest
+import numpy
+
+class TestShapes(unittest.TestCase):
+
+ def testShapes(self):
+ a1 = numpy.array([(0,1),(2,3)])
+ a1_shape = (1,4)
+ a1 = shapes_ext.reshape(a1,a1_shape)
+ self.assertEqual(a1_shape,a1.shape)
+
+if __name__=="__main__":
+ unittest.main()
diff --git a/src/boost/libs/python/test/numpy/templates.cpp b/src/boost/libs/python/test/numpy/templates.cpp
new file mode 100644
index 000000000..83de6bd2f
--- /dev/null
+++ b/src/boost/libs/python/test/numpy/templates.cpp
@@ -0,0 +1,63 @@
+// Copyright Jim Bosch & Ankit Daftery 2010-2012.
+// Copyright Stefan Seefeld 2016.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/python/numpy.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/mpl/vector_c.hpp>
+
+namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+struct ArrayFiller
+{
+
+ typedef boost::mpl::vector< short, int, float, std::complex<double> > TypeSequence;
+ typedef boost::mpl::vector_c< int, 1, 2 > DimSequence;
+
+ explicit ArrayFiller(np::ndarray const & arg) : argument(arg) {}
+
+ template <typename T, int N>
+ void apply() const
+ {
+ if (N == 1)
+ {
+ char * p = argument.get_data();
+ int stride = argument.strides(0);
+ int size = argument.shape(0);
+ for (int n = 0; n != size; ++n, p += stride)
+ *reinterpret_cast<T*>(p) = static_cast<T>(n);
+ }
+ else
+ {
+ char * row_p = argument.get_data();
+ int row_stride = argument.strides(0);
+ int col_stride = argument.strides(1);
+ int rows = argument.shape(0);
+ int cols = argument.shape(1);
+ int i = 0;
+ for (int n = 0; n != rows; ++n, row_p += row_stride)
+ {
+ char * col_p = row_p;
+ for (int m = 0; m != cols; ++i, ++m, col_p += col_stride)
+ *reinterpret_cast<T*>(col_p) = static_cast<T>(i);
+ }
+ }
+ }
+
+ np::ndarray argument;
+};
+
+void fill(np::ndarray const & arg)
+{
+ ArrayFiller filler(arg);
+ np::invoke_matching_array<ArrayFiller::TypeSequence, ArrayFiller::DimSequence >(arg, filler);
+}
+
+BOOST_PYTHON_MODULE(templates_ext)
+{
+ np::initialize();
+ p::def("fill", fill);
+}
diff --git a/src/boost/libs/python/test/numpy/templates.py b/src/boost/libs/python/test/numpy/templates.py
new file mode 100755
index 000000000..8290b13a0
--- /dev/null
+++ b/src/boost/libs/python/test/numpy/templates.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright Jim Bosch & Ankit Daftery 2010-2012.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+import templates_ext
+import unittest
+import numpy
+
+class TestTemplates(unittest.TestCase):
+
+ def testTemplates(self):
+ for dtype in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128):
+ v = numpy.arange(12, dtype=dtype)
+ for shape in ((12,), (4, 3), (2, 6)):
+ a1 = numpy.zeros(shape, dtype=dtype)
+ a2 = v.reshape(a1.shape)
+ templates_ext.fill(a1)
+ self.assert_((a1 == a2).all())
+ a1 = numpy.zeros((12,), dtype=numpy.float64)
+ self.assertRaises(TypeError, templates_ext.fill, a1)
+ a1 = numpy.zeros((12,2,3), dtype=numpy.float32)
+ self.assertRaises(TypeError, templates_ext.fill, a1)
+
+if __name__=="__main__":
+ unittest.main()
diff --git a/src/boost/libs/python/test/numpy/ufunc.cpp b/src/boost/libs/python/test/numpy/ufunc.cpp
new file mode 100644
index 000000000..3a9d43cbb
--- /dev/null
+++ b/src/boost/libs/python/test/numpy/ufunc.cpp
@@ -0,0 +1,36 @@
+// Copyright Jim Bosch & Ankit Daftery 2010-2012.
+// Copyright Stefan Seefeld 2016.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/python/numpy.hpp>
+
+namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+struct UnaryCallable
+{
+ typedef double argument_type;
+ typedef double result_type;
+
+ double operator()(double r) const { return r * 2;}
+};
+
+struct BinaryCallable
+{
+ typedef double first_argument_type;
+ typedef double second_argument_type;
+ typedef double result_type;
+
+ double operator()(double a, double b) const { return a * 2 + b * 3;}
+};
+
+BOOST_PYTHON_MODULE(ufunc_ext)
+{
+ np::initialize();
+ p::class_<UnaryCallable>("UnaryCallable")
+ .def("__call__", np::unary_ufunc<UnaryCallable>::make());
+ p::class_< BinaryCallable>("BinaryCallable")
+ .def("__call__", np::binary_ufunc<BinaryCallable>::make());
+}
diff --git a/src/boost/libs/python/test/numpy/ufunc.py b/src/boost/libs/python/test/numpy/ufunc.py
new file mode 100755
index 000000000..e820121ee
--- /dev/null
+++ b/src/boost/libs/python/test/numpy/ufunc.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+# Copyright Jim Bosch & Ankit Daftery 2010-2012.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+import ufunc_ext
+import unittest
+import numpy
+from numpy.testing.utils import assert_array_almost_equal
+
+class TestUnary(unittest.TestCase):
+
+ def testScalar(self):
+ f = ufunc_ext.UnaryCallable()
+ assert_array_almost_equal(f(1.0), 2.0)
+ assert_array_almost_equal(f(3.0), 6.0)
+
+ def testArray(self):
+ f = ufunc_ext.UnaryCallable()
+ a = numpy.arange(5, dtype=float)
+ b = f(a)
+ assert_array_almost_equal(b, a*2.0)
+ c = numpy.zeros(5, dtype=float)
+ d = f(a,output=c)
+ self.assert_(c is d)
+ assert_array_almost_equal(d, a*2.0)
+
+ def testList(self):
+ f = ufunc_ext.UnaryCallable()
+ a = range(5)
+ b = f(a)
+ assert_array_almost_equal(b/2.0, a)
+
+class TestBinary(unittest.TestCase):
+
+ def testScalar(self):
+ f = ufunc_ext.BinaryCallable()
+ assert_array_almost_equal(f(1.0, 3.0), 11.0)
+ assert_array_almost_equal(f(3.0, 2.0), 12.0)
+
+ def testArray(self):
+ f = ufunc_ext.BinaryCallable()
+ a = numpy.random.randn(5)
+ b = numpy.random.randn(5)
+ assert_array_almost_equal(f(a,b), (a*2+b*3))
+ c = numpy.zeros(5, dtype=float)
+ d = f(a,b,output=c)
+ self.assert_(c is d)
+ assert_array_almost_equal(d, a*2 + b*3)
+ assert_array_almost_equal(f(a, 2.0), a*2 + 6.0)
+ assert_array_almost_equal(f(1.0, b), 2.0 + b*3)
+
+
+if __name__=="__main__":
+ unittest.main()