ToNumpy.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <Python.h>
7 #include <array>
8 #include <cstdlib>
9 
11 // IWYU pragma: no_include <numpy/ndarrayobject.h>
12 // IWYU pragma: no_include <numpy/ndarraytypes.h>
13 
14 namespace py_bindings {
15 /// Convert Matrix to a Numpy Array. Always creates a copy.
16 // We use `malloc` instead of `new` because we tell NumPy it needs to free the
17 // memory and NumPy uses `free`, not `delete`.
18 inline PyObject* to_numpy(const Matrix& matrix) {
19  auto* c_style_data = static_cast<double*>(
20  malloc(sizeof(double) * (matrix.rows()) * matrix.columns()));
21  for (size_t i = 0; i < matrix.rows(); ++i) {
22  for (size_t j = 0; j < matrix.columns(); ++j) {
23  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
24  c_style_data[j + i * matrix.columns()] = matrix(i, j);
25  }
26  }
28  {static_cast<long>(matrix.rows()), static_cast<long>(matrix.columns())}};
29  // clang-tidy: C-style cast done implictly with Python
30  // NOLINTNEXTLINE
31  PyObject* npy_array = PyArray_SimpleNewFromData(2, dims.data(), NPY_DOUBLE,
32  c_style_data); // NOLINT
33 
34  // The `reinterpret_cast` is intentional because we know the pointer actually
35  // points to an object of type `PyArrayObject` and we need to access it in
36  // that manner.
37 
38  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
39  auto* npy_array_obj = reinterpret_cast<PyArrayObject*>(npy_array);
40  PyArray_ENABLEFLAGS(npy_array_obj, NPY_ARRAY_OWNDATA);
41  return npy_array;
42 }
43 } // namespace py_bindings
Defines class Matrix.
Definition: Bindings.cpp:25
A dynamically sized matrix of doubles with column-major storage.
Definition: Matrix.hpp:19
T malloc(T... args)