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 #include "DataStructures/Python/Numpy.hpp"
12 
13 // IWYU pragma: no_include <numpy/ndarrayobject.h>
14 // IWYU pragma: no_include <numpy/ndarraytypes.h>
15 
16 namespace py_bindings {
17 /// Convert Matrix to a Numpy Array. Always creates a copy.
18 // We use `malloc` instead of `new` because we tell NumPy it needs to free the
19 // memory and NumPy uses `free`, not `delete`.
20 inline PyObject* to_numpy(const Matrix& matrix) {
21  auto* c_style_data = static_cast<double*>(
22  malloc(sizeof(double) * (matrix.rows()) * matrix.columns()));
23  for (size_t i = 0; i < matrix.rows(); ++i) {
24  for (size_t j = 0; j < matrix.columns(); ++j) {
25  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
26  c_style_data[j + i * matrix.columns()] = matrix(i, j);
27  }
28  }
30  {static_cast<long>(matrix.rows()), static_cast<long>(matrix.columns())}};
31  // clang-tidy: C-style cast done implictly with Python
32  // NOLINTNEXTLINE
33  PyObject* npy_array = PyArray_SimpleNewFromData(2, dims.data(), NPY_DOUBLE,
34  c_style_data); // NOLINT
35 
36  // The `reinterpret_cast` is intentional because we know the pointer actually
37  // points to an object of type `PyArrayObject` and we need to access it in
38  // that manner.
39 
40  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
41  auto* npy_array_obj = reinterpret_cast<PyArrayObject*>(npy_array);
42  PyArray_ENABLEFLAGS(npy_array_obj, NPY_ARRAY_OWNDATA);
43  return npy_array;
44 }
45 } // 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)