eigenpy 3.12.0
Bindings between Numpy and Eigen using Boost.Python
Loading...
Searching...
No Matches
eigen-from-python.hpp
1//
2// Copyright (c) 2024-2025 INRIA
3//
4
5#ifndef __eigenpy_sparse_eigen_from_python_hpp__
6#define __eigenpy_sparse_eigen_from_python_hpp__
7
8#include "eigenpy/fwd.hpp"
9#include "eigenpy/eigen-allocator.hpp"
10#include "eigenpy/scipy-type.hpp"
11#include "eigenpy/scalar-conversion.hpp"
12
13namespace eigenpy {
14
15template <typename SparseMatrixType>
16struct expected_pytype_for_arg<SparseMatrixType,
17 Eigen::SparseMatrixBase<SparseMatrixType>> {
18 static PyTypeObject const *get_pytype() {
19 PyTypeObject const *py_type = ScipyType::get_pytype<SparseMatrixType>();
20 return py_type;
21 }
22};
23
24} // namespace eigenpy
25
26namespace boost {
27namespace python {
28namespace converter {
29
30template <typename Scalar, int Options, typename StorageIndex>
31struct expected_pytype_for_arg<
32 Eigen::SparseMatrix<Scalar, Options, StorageIndex>>
34 Eigen::SparseMatrix<Scalar, Options, StorageIndex>> {};
35
36template <typename Scalar, int Options, typename StorageIndex>
37struct rvalue_from_python_data<
38 Eigen::SparseMatrix<Scalar, Options, StorageIndex> const &>
40 Eigen::SparseMatrix<Scalar, Options, StorageIndex> const &> {
41 typedef Eigen::SparseMatrix<Scalar, Options, StorageIndex> T;
42 EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(T const &)
43};
44
45template <typename Derived>
46struct rvalue_from_python_data<Eigen::SparseMatrixBase<Derived> const &>
47 : ::eigenpy::rvalue_from_python_data<Derived const &> {
48 EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(Derived const &)
49};
50
51} // namespace converter
52} // namespace python
53} // namespace boost
54
55namespace boost {
56namespace python {
57namespace detail {
58// template <typename TensorType>
59// struct referent_storage<Eigen::TensorRef<TensorType> &> {
60// typedef Eigen::TensorRef<TensorType> RefType;
61// typedef ::eigenpy::details::referent_storage_eigen_ref<RefType>
62// StorageType; typedef typename ::eigenpy::aligned_storage<
63// referent_size<StorageType &>::value>::type type;
64// };
65
66// template <typename TensorType>
67// struct referent_storage<const Eigen::TensorRef<const TensorType> &> {
68// typedef Eigen::TensorRef<const TensorType> RefType;
69// typedef ::eigenpy::details::referent_storage_eigen_ref<RefType>
70// StorageType; typedef typename ::eigenpy::aligned_storage<
71// referent_size<StorageType &>::value>::type type;
72// };
73} // namespace detail
74} // namespace python
75} // namespace boost
76
77namespace eigenpy {
78
79template <typename SparseMatrixType>
80struct eigen_from_py_impl<SparseMatrixType,
81 Eigen::SparseMatrixBase<SparseMatrixType>> {
82 typedef typename SparseMatrixType::Scalar Scalar;
83
85 static void *convertible(PyObject *pyObj);
86
88 static void construct(PyObject *pyObj,
89 bp::converter::rvalue_from_python_stage1_data *memory);
90
91 static void registration();
92};
93
94template <typename SparseMatrixType>
96 SparseMatrixType,
97 Eigen::SparseMatrixBase<SparseMatrixType>>::convertible(PyObject *pyObj) {
98 const PyTypeObject *type = Py_TYPE(pyObj);
99 const PyTypeObject *sparse_matrix_py_type =
100 ScipyType::get_pytype<SparseMatrixType>();
101 typedef typename SparseMatrixType::Scalar Scalar;
102
103 if (type != sparse_matrix_py_type) return 0;
104
105 bp::object obj(bp::handle<>(bp::borrowed(pyObj)));
106
107 const int type_num = ScipyType::get_numpy_type_num(obj);
108
109 if (!np_type_is_convertible_into_scalar<Scalar>(type_num)) return 0;
110
111 return pyObj;
112}
113
114template <typename MatOrRefType>
115void eigen_sparse_matrix_from_py_construct(
116 PyObject *pyObj, bp::converter::rvalue_from_python_stage1_data *memory) {
117 typedef typename MatOrRefType::Scalar Scalar;
118 typedef typename MatOrRefType::StorageIndex StorageIndex;
119
120 typedef Eigen::Map<MatOrRefType> MapMatOrRefType;
121
122 bp::converter::rvalue_from_python_storage<MatOrRefType> *storage =
123 reinterpret_cast<
124 bp::converter::rvalue_from_python_storage<MatOrRefType> *>(
125 reinterpret_cast<void *>(memory));
126 void *raw_ptr = storage->storage.bytes;
127
128 bp::object obj(bp::handle<>(bp::borrowed(pyObj)));
129
130 const int type_num_python_sparse_matrix = ScipyType::get_numpy_type_num(obj);
131 const int type_num_eigen_sparse_matrix = Register::getTypeCode<Scalar>();
132
133 if (type_num_eigen_sparse_matrix == type_num_python_sparse_matrix) {
134 typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> DataVector;
135 // typedef const Eigen::Ref<const DataVector> RefDataVector;
136 DataVector data = bp::extract<DataVector>(obj.attr("data"));
137 bp::tuple shape = bp::extract<bp::tuple>(obj.attr("shape"));
138 typedef Eigen::Matrix<StorageIndex, Eigen::Dynamic, 1> StorageIndexVector;
139 // typedef const Eigen::Ref<const StorageIndexVector>
140 // RefStorageIndexVector;
141 StorageIndexVector indices =
142 bp::extract<StorageIndexVector>(obj.attr("indices"));
143 StorageIndexVector indptr =
144 bp::extract<StorageIndexVector>(obj.attr("indptr"));
145
146 const Eigen::Index m = bp::extract<Eigen::Index>(shape[0]),
147 n = bp::extract<Eigen::Index>(shape[1]),
148 nnz = bp::extract<Eigen::Index>(obj.attr("nnz"));
149
150 // Handle the specific case of the null matrix
151 Scalar *data_ptr = nullptr;
152 StorageIndex *indices_ptr = nullptr;
153 if (nnz > 0) {
154 data_ptr = data.data();
155 indices_ptr = indices.data();
156 }
157 MapMatOrRefType sparse_map(m, n, nnz, indptr.data(), indices_ptr, data_ptr);
158
159#if EIGEN_VERSION_AT_LEAST(3, 4, 90)
160 sparse_map.sortInnerIndices();
161#endif
162
163 new (raw_ptr) MatOrRefType(sparse_map);
164 }
165
166 memory->convertible = storage->storage.bytes;
167}
168
169template <typename SparseMatrixType>
170void eigen_from_py_impl<SparseMatrixType,
171 Eigen::SparseMatrixBase<SparseMatrixType>>::
172 construct(PyObject *pyObj,
173 bp::converter::rvalue_from_python_stage1_data *memory) {
174 eigen_sparse_matrix_from_py_construct<SparseMatrixType>(pyObj, memory);
175}
176
177template <typename SparseMatrixType>
179 SparseMatrixType,
180 Eigen::SparseMatrixBase<SparseMatrixType>>::registration() {
181 bp::converter::registry::push_back(
182 reinterpret_cast<void *(*)(_object *)>(&eigen_from_py_impl::convertible),
183 &eigen_from_py_impl::construct, bp::type_id<SparseMatrixType>()
184#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
185 ,
187#endif
188 );
189}
190
191template <typename SparseMatrixType>
192struct eigen_from_py_converter_impl<SparseMatrixType,
193 Eigen::SparseMatrixBase<SparseMatrixType>> {
194 static void registration() {
195 EigenFromPy<SparseMatrixType>::registration();
196
197 // Add conversion to Eigen::SparseMatrixBase<SparseMatrixType>
198 typedef Eigen::SparseMatrixBase<SparseMatrixType> SparseMatrixBase;
199 EigenFromPy<SparseMatrixBase>::registration();
200
201 // // Add conversion to Eigen::Ref<SparseMatrixType>
202 // typedef Eigen::Ref<SparseMatrixType> RefType;
203 // EigenFromPy<SparseMatrixType>::registration();
204 //
205 // // Add conversion to Eigen::Ref<const SparseMatrixType>
206 // typedef const Eigen::Ref<const SparseMatrixType> ConstRefType;
207 // EigenFromPy<ConstRefType>::registration();
208 }
209};
210
211template <typename SparseMatrixType>
212struct EigenFromPy<Eigen::SparseMatrixBase<SparseMatrixType>>
213 : EigenFromPy<SparseMatrixType> {
214 typedef EigenFromPy<SparseMatrixType> EigenFromPyDerived;
215 typedef Eigen::SparseMatrixBase<SparseMatrixType> Base;
216
217 static void registration() {
218 bp::converter::registry::push_back(
219 reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
220 &EigenFromPy::construct, bp::type_id<Base>()
221#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
222 ,
224#endif
225 );
226 }
227};
228//
229// template <typename TensorType>
230// struct EigenFromPy<Eigen::TensorRef<TensorType> > {
231// typedef Eigen::TensorRef<TensorType> RefType;
232// typedef typename TensorType::Scalar Scalar;
233//
234// /// \brief Determine if pyObj can be converted into a MatType object
235// static void *convertible(PyObject *pyObj) {
236// if (!call_PyArray_Check(pyObj)) return 0;
237// PyArrayObject *pyArray = reinterpret_cast<PyArrayObject *>(pyObj);
238// if (!PyArray_ISWRITEABLE(pyArray)) return 0;
239// return EigenFromPy<TensorType>::convertible(pyObj);
240// }
241//
242// static void registration() {
243// bp::converter::registry::push_back(
244// reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
245// &eigen_from_py_construct<RefType>, bp::type_id<RefType>()
246// #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
247// ,
248// &eigenpy::expected_pytype_for_arg<TensorType>::get_pytype
249// #endif
250// );
251// }
252//};
253
254// template <typename TensorType>
255// struct EigenFromPy<const Eigen::TensorRef<const TensorType> > {
256// typedef const Eigen::TensorRef<const TensorType> ConstRefType;
257// typedef typename TensorType::Scalar Scalar;
258//
259// /// \brief Determine if pyObj can be converted into a MatType object
260// static void *convertible(PyObject *pyObj) {
261// return EigenFromPy<TensorType>::convertible(pyObj);
262// }
263//
264// static void registration() {
265// bp::converter::registry::push_back(
266// reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
267// &eigen_from_py_construct<ConstRefType>, bp::type_id<ConstRefType>()
268// #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
269// ,
270// &eigenpy::expected_pytype_for_arg<TensorType>::get_pytype
271// #endif
272// );
273// }
274// };
275
276} // namespace eigenpy
277
278#endif // __eigenpy_sparse_eigen_from_python_hpp__
static void * convertible(PyObject *pyObj)
Determine if pyObj can be converted into a MatType object.
static void construct(PyObject *pyObj, bp::converter::rvalue_from_python_stage1_data *memory)
Allocate memory and copy pyObj in the new storage.
static void * convertible(PyObject *pyObj)
Determine if pyObj can be converted into a MatType object.