From adfd33a1aa7d12296b44f23fa52fc4519bc39c22 Mon Sep 17 00:00:00 2001 From: Hans Dembinski Date: Fri, 24 Mar 2017 22:54:25 +0100 Subject: [PATCH] fix for cpp_int numpy conversion --- src/python/histogram.cpp | 40 ++++++++++++++++++++++++++++-------- test/python_suite_test.py.in | 10 +++++---- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/python/histogram.cpp b/src/python/histogram.cpp index 19226a64..bb4f39d3 100644 --- a/src/python/histogram.cpp +++ b/src/python/histogram.cpp @@ -273,12 +273,6 @@ struct storage_access { python::object array_interface(dynamic_histogram<>& self) { auto& b = self.storage_.buffer_; - if (b.type_.id_ == 5) { - // PyErr_SetString(PyExc_KeyError, "cannot convert multiprecision storage to numpy array"); - // python::throw_error_already_set(); - // workaround: for some reason, exception is ignored here - return python::object(); - } if (b.type_.id_ == 0) { // buffer not created yet, do that now @@ -289,6 +283,33 @@ struct storage_access { python::list shapes; python::list strides; std::size_t stride = 1; + if (b.type_.id_ == 5) { + // cannot pass cpp_int to numpy, so make + // a double array, fill it, and pass that to python + npy_intp shapes2[BOOST_HISTOGRAM_AXIS_LIMIT]; + npy_intp strides2[BOOST_HISTOGRAM_AXIS_LIMIT]; + stride = sizeof(double); + d["typestr"] = python::str("|f") + python::str(stride); + for (unsigned i = 0; i < self.dim(); ++i) { + const auto s = shape(self.axis(i)); + shapes2[i] = s; + strides2[i] = s; + shapes.append(s); + strides.append(stride); + stride *= s; + } + PyObject* ptr = PyArray_SimpleNew(self.dim(), shapes2, NPY_DOUBLE); + for (unsigned i = 0; i < self.dim(); ++i) + PyArray_STRIDES((PyArrayObject*)ptr)[i] = strides2[i]; + double* buf = (double*)PyArray_DATA((PyArrayObject*)ptr); + for (unsigned i = 0; i < b.size_; ++i) + buf[i] = static_cast(b.template at(i)); + d["shape"] = python::tuple(shapes); + d["strides"] = python::tuple(strides); + d["data"] = python::object(python::handle<>(ptr)); + return d; + } + if (b.type_.id_ == 6) { stride *= sizeof(double); d["typestr"] = python::str("|f") + python::str(stride); @@ -300,13 +321,14 @@ struct storage_access { d["typestr"] = python::str("|u") + python::str(stride); } for (unsigned i = 0; i < self.dim(); ++i) { - shapes.append(shape(self.axis(i))); + const auto s = shape(self.axis(i)); + shapes.append(s); strides.append(stride); - stride *= shape(self.axis(i)); + stride *= s; } d["shape"] = python::tuple(shapes); - d["data"] = python::make_tuple(reinterpret_cast(b.ptr_), false); d["strides"] = python::tuple(strides); + d["data"] = python::make_tuple(reinterpret_cast(b.ptr_), false); return d; } }; diff --git a/test/python_suite_test.py.in b/test/python_suite_test.py.in index 396a96b8..c6c3b2b1 100755 --- a/test/python_suite_test.py.in +++ b/test/python_suite_test.py.in @@ -657,14 +657,16 @@ class histogramtest(unittest.TestCase): self.assertEqual(b1, 0) @unittest.skipUnless(have_numpy, "requires build with numpy-support") - def test_bad_numpy_conversion(self): - a = histogram(integer_axis(0, 0)) + def test_numpy_conversion_5(self): + a = histogram(integer_axis(0, 1, uoflow=False)) a.fill(0) for i in xrange(80): a += a # a now holds a multiprecision type - with self.assertRaises(ValueError): - numpy.asarray(a) + a1 = numpy.asarray(a) + self.assertEqual(a1.shape, (2,)) + self.assertEqual(a1[0], float(2 ** 80)) + self.assertEqual(a1[1], 0) @unittest.skipUnless(have_numpy, "requires build with numpy-support") def test_fill_with_numpy_array_0(self):