diff options
Diffstat (limited to 'ext/pybind11/docs/advanced/pycpp/numpy.rst')
-rw-r--r-- | ext/pybind11/docs/advanced/pycpp/numpy.rst | 79 |
1 files changed, 33 insertions, 46 deletions
diff --git a/ext/pybind11/docs/advanced/pycpp/numpy.rst b/ext/pybind11/docs/advanced/pycpp/numpy.rst index 6bcc46719..98b0c25b9 100644 --- a/ext/pybind11/docs/advanced/pycpp/numpy.rst +++ b/ext/pybind11/docs/advanced/pycpp/numpy.rst @@ -57,11 +57,11 @@ specification. struct buffer_info { void *ptr; - size_t itemsize; + ssize_t itemsize; std::string format; - int ndim; - std::vector<size_t> shape; - std::vector<size_t> strides; + ssize_t ndim; + std::vector<ssize_t> shape; + std::vector<ssize_t> strides; }; To create a C++ function that can take a Python buffer object as an argument, @@ -95,11 +95,11 @@ buffer objects (e.g. a NumPy matrix). throw std::runtime_error("Incompatible buffer dimension!"); auto strides = Strides( - info.strides[rowMajor ? 0 : 1] / sizeof(Scalar), - info.strides[rowMajor ? 1 : 0] / sizeof(Scalar)); + info.strides[rowMajor ? 0 : 1] / (py::ssize_t)sizeof(Scalar), + info.strides[rowMajor ? 1 : 0] / (py::ssize_t)sizeof(Scalar)); auto map = Eigen::Map<Matrix, 0, Strides>( - static_cat<Scalar *>(info.ptr), info.shape[0], info.shape[1], strides); + static_cast<Scalar *>(info.ptr), info.shape[0], info.shape[1], strides); new (&m) Matrix(map); }); @@ -111,18 +111,14 @@ as follows: .def_buffer([](Matrix &m) -> py::buffer_info { return py::buffer_info( - m.data(), /* Pointer to buffer */ - sizeof(Scalar), /* Size of one scalar */ - /* Python struct-style format descriptor */ - py::format_descriptor<Scalar>::format(), - /* Number of dimensions */ - 2, - /* Buffer dimensions */ - { (size_t) m.rows(), - (size_t) m.cols() }, - /* Strides (in bytes) for each index */ + m.data(), /* Pointer to buffer */ + sizeof(Scalar), /* Size of one scalar */ + py::format_descriptor<Scalar>::format(), /* Python struct-style format descriptor */ + 2, /* Number of dimensions */ + { m.rows(), m.cols() }, /* Buffer dimensions */ { sizeof(Scalar) * (rowMajor ? m.cols() : 1), sizeof(Scalar) * (rowMajor ? 1 : m.rows()) } + /* Strides (in bytes) for each index */ ); }) @@ -194,7 +190,7 @@ expects the type followed by field names: }; // ... - PYBIND11_PLUGIN(test) { + PYBIND11_MODULE(test, m) { // ... PYBIND11_NUMPY_DTYPE(A, x, y); @@ -202,6 +198,13 @@ expects the type followed by field names: /* now both A and B can be used as template arguments to py::array_t */ } +The structure should consist of fundamental arithmetic types, ``std::complex``, +previously registered substructures, and arrays of any of the above. Both C++ +arrays and ``std::array`` are supported. While there is a static assertion to +prevent many types of unsupported structures, it is still the user's +responsibility to use only "plain" structures that can be safely manipulated as +raw memory without violating invariants. + Vectorizing functions ===================== @@ -236,27 +239,13 @@ by the compiler. The result is returned as a NumPy array of type The scalar argument ``z`` is transparently replicated 4 times. The input arrays ``x`` and ``y`` are automatically converted into the right types (they are of type ``numpy.dtype.int64`` but need to be ``numpy.dtype.int32`` and -``numpy.dtype.float32``, respectively) - -Sometimes we might want to explicitly exclude an argument from the vectorization -because it makes little sense to wrap it in a NumPy array. For instance, -suppose the function signature was - -.. code-block:: cpp +``numpy.dtype.float32``, respectively). - double my_func(int x, float y, my_custom_type *z); +.. note:: -This can be done with a stateful Lambda closure: - -.. code-block:: cpp - - // Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the vectorization) - m.def("vectorized_func", - [](py::array_t<int> x, py::array_t<float> y, my_custom_type *z) { - auto stateful_closure = [z](int x, float y) { return my_func(x, y, z); }; - return py::vectorize(stateful_closure)(x, y); - } - ); + Only arithmetic, complex, and POD types passed by value or by ``const &`` + reference are vectorized; all other arguments are passed through as-is. + Functions taking rvalue reference arguments cannot be vectorized. In cases where the computation is too complicated to be reduced to ``vectorize``, it will be necessary to create and access the buffer contents @@ -295,10 +284,8 @@ simply using ``vectorize``). return result; } - PYBIND11_PLUGIN(test) { - py::module m("test"); + PYBIND11_MODULE(test, m) { m.def("add_arrays", &add_arrays, "Add two NumPy arrays"); - return m.ptr(); } .. seealso:: @@ -322,17 +309,17 @@ where ``N`` gives the required dimensionality of the array: m.def("sum_3d", [](py::array_t<double> x) { auto r = x.unchecked<3>(); // x must have ndim = 3; can be non-writeable double sum = 0; - for (size_t i = 0; i < r.shape(0); i++) - for (size_t j = 0; j < r.shape(1); j++) - for (size_t k = 0; k < r.shape(2); k++) + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) sum += r(i, j, k); return sum; }); m.def("increment_3d", [](py::array_t<double> x) { auto r = x.mutable_unchecked<3>(); // Will throw if ndim != 3 or flags.writeable is false - for (size_t i = 0; i < r.shape(0); i++) - for (size_t j = 0; j < r.shape(1); j++) - for (size_t k = 0; k < r.shape(2); k++) + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) r(i, j, k) += 1.0; }, py::arg().noconvert()); |