μHAL (v2.8.17)
Part of the IPbus software repository
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
matrix.h
Go to the documentation of this file.
1/*
2 pybind11/eigen/matrix.h: Transparent conversion for dense and sparse Eigen matrices
3
4 Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
5
6 All rights reserved. Use of this source code is governed by a
7 BSD-style license that can be found in the LICENSE file.
8*/
9
10#pragma once
11
12#include "../numpy.h"
13
14/* HINT: To suppress warnings originating from the Eigen headers, use -isystem.
15 See also:
16 https://stackoverflow.com/questions/2579576/i-dir-vs-isystem-dir
17 https://stackoverflow.com/questions/1741816/isystem-for-ms-visual-studio-c-compiler
18*/
19PYBIND11_WARNING_PUSH
20PYBIND11_WARNING_DISABLE_MSVC(5054) // https://github.com/pybind/pybind11/pull/3741
21// C5054: operator '&': deprecated between enumerations of different types
22#if defined(__MINGW32__)
23PYBIND11_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
24#endif
25
26#include <Eigen/Core>
27#include <Eigen/SparseCore>
28
30
31// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit
32// move constructors that break things. We could detect this an explicitly copy, but an extra copy
33// of matrices seems highly undesirable.
34static_assert(EIGEN_VERSION_AT_LEAST(3, 2, 7),
35 "Eigen matrix support in pybind11 requires Eigen >= 3.2.7");
36
38
40
41// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides:
42using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
43template <typename MatrixType>
44using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
45template <typename MatrixType>
46using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
47
49
50#if EIGEN_VERSION_AT_LEAST(3, 3, 0)
51using EigenIndex = Eigen::Index;
52template <typename Scalar, int Flags, typename StorageIndex>
53using EigenMapSparseMatrix = Eigen::Map<Eigen::SparseMatrix<Scalar, Flags, StorageIndex>>;
54#else
55using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
56template <typename Scalar, int Flags, typename StorageIndex>
57using EigenMapSparseMatrix = Eigen::MappedSparseMatrix<Scalar, Flags, StorageIndex>;
58#endif
59
60// Matches Eigen::Map, Eigen::Ref, blocks, etc:
61template <typename T>
63 std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
64template <typename T>
65using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
66template <typename T>
69template <typename T>
71// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above. This
72// basically covers anything that can be assigned to a dense matrix but that don't have a typical
73// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and
74// SelfAdjointView fall into this category.
75template <typename T>
79
80// Captures numpy/eigen conformability status (returned by EigenProps::conformable()):
81template <bool EigenRowMajor>
82struct EigenConformable {
83 bool conformable = false;
84 EigenIndex rows = 0, cols = 0;
85 EigenDStride stride{0, 0}; // Only valid if negativestrides is false!
86 bool negativestrides = false; // If true, do not use stride!
87
88 // NOLINTNEXTLINE(google-explicit-constructor)
89 EigenConformable(bool fits = false) : conformable{fits} {}
90 // Matrix type:
92 : conformable{true}, rows{r}, cols{c},
93 // TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity.
94 // http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747
95 stride{EigenRowMajor ? (rstride > 0 ? rstride : 0)
96 : (cstride > 0 ? cstride : 0) /* outer stride */,
97 EigenRowMajor ? (cstride > 0 ? cstride : 0)
98 : (rstride > 0 ? rstride : 0) /* inner stride */},
99 negativestrides{rstride < 0 || cstride < 0} {}
100 // Vector type:
102 : EigenConformable(r, c, r == 1 ? c * stride : stride, c == 1 ? r : r * stride) {}
103
104 template <typename props>
105 bool stride_compatible() const {
106 // To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
107 // matching strides, or a dimension size of 1 (in which case the stride value is
108 // irrelevant). Alternatively, if any dimension size is 0, the strides are not relevant
109 // (and numpy ≥ 1.23 sets the strides to 0 in that case, so we need to check explicitly).
110 if (negativestrides) {
111 return false;
112 }
113 if (rows == 0 || cols == 0) {
114 return true;
115 }
116 return (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner()
117 || (EigenRowMajor ? cols : rows) == 1)
118 && (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer()
119 || (EigenRowMajor ? rows : cols) == 1);
120 }
121 // NOLINTNEXTLINE(google-explicit-constructor)
122 operator bool() const { return conformable; }
123};
124
125template <typename Type>
127 using type = Type;
128};
129template <typename PlainObjectType, int MapOptions, typename StrideType>
130struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> {
131 using type = StrideType;
132};
133template <typename PlainObjectType, int Options, typename StrideType>
134struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> {
135 using type = StrideType;
136};
137
138// Helper struct for extracting information from an Eigen type
139template <typename Type_>
140struct EigenProps {
141 using Type = Type_;
142 using Scalar = typename Type::Scalar;
144 static constexpr EigenIndex rows = Type::RowsAtCompileTime, cols = Type::ColsAtCompileTime,
145 size = Type::SizeAtCompileTime;
146 static constexpr bool row_major = Type::IsRowMajor,
147 vector
148 = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1
149 fixed_rows = rows != Eigen::Dynamic, fixed_cols = cols != Eigen::Dynamic,
150 fixed = size != Eigen::Dynamic, // Fully-fixed size
151 dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size
152
153 template <EigenIndex i, EigenIndex ifzero>
154 using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
155 static constexpr EigenIndex inner_stride
157 outer_stride = if_zero < StrideType::OuterStrideAtCompileTime,
158 vector ? size
159 : row_major ? cols
160 : rows > ::value;
161 static constexpr bool dynamic_stride
162 = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
163 static constexpr bool requires_row_major
165 static constexpr bool requires_col_major
167
168 // Takes an input array and determines whether we can make it fit into the Eigen type. If
169 // the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector
170 // (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).
172 const auto dims = a.ndim();
173 if (dims < 1 || dims > 2) {
174 return false;
175 }
176
177 if (dims == 2) { // Matrix type: require exact match (or dynamic)
178
179 EigenIndex np_rows = a.shape(0), np_cols = a.shape(1),
180 np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),
181 np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));
182 if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols)) {
183 return false;
184 }
185
186 return {np_rows, np_cols, np_rstride, np_cstride};
187 }
188
189 // Otherwise we're storing an n-vector. Only one of the strides will be used, but
190 // whichever is used, we want the (single) numpy stride value.
191 const EigenIndex n = a.shape(0),
192 stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));
193
194 if (vector) { // Eigen type is a compile-time vector
195 if (fixed && size != n) {
196 return false; // Vector size mismatch
197 }
198 return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
199 }
200 if (fixed) {
201 // The type has a fixed size, but is not a vector: abort
202 return false;
203 }
204 if (fixed_cols) {
205 // Since this isn't a vector, cols must be != 1. We allow this only if it exactly
206 // equals the number of elements (rows is Dynamic, and so 1 row is allowed).
207 if (cols != n) {
208 return false;
209 }
210 return {1, n, stride};
211 } // Otherwise it's either fully dynamic, or column dynamic; both become a column vector
212 if (fixed_rows && rows != n) {
213 return false;
214 }
215 return {n, 1, stride};
216 }
217
218 static constexpr bool show_writeable
220 static constexpr bool show_order = is_eigen_dense_map<Type>::value;
221 static constexpr bool show_c_contiguous = show_order && requires_row_major;
222 static constexpr bool show_f_contiguous
224
225 static constexpr auto descriptor
227 + const_name<fixed_rows>(const_name<(size_t) rows>(), const_name("m")) + const_name(", ")
228 + const_name<fixed_cols>(const_name<(size_t) cols>(), const_name("n")) + const_name("]")
229 +
230 // For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to
231 // be satisfied: writeable=True (for a mutable reference), and, depending on the map's
232 // stride options, possibly f_contiguous or c_contiguous. We include them in the
233 // descriptor output to provide some hint as to why a TypeError is occurring (otherwise
234 // it can be confusing to see that a function accepts a 'numpy.ndarray[float64[3,2]]' and
235 // an error message that you *gave* a numpy.ndarray of the right type and dimensions.
236 const_name<show_writeable>(", flags.writeable", "")
237 + const_name<show_c_contiguous>(", flags.c_contiguous", "")
238 + const_name<show_f_contiguous>(", flags.f_contiguous", "") + const_name("]");
239};
240
241// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
242// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array.
243template <typename props>
244handle
245eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
246 constexpr ssize_t elem_size = sizeof(typename props::Scalar);
247 array a;
248 if (props::vector) {
249 a = array({src.size()}, {elem_size * src.innerStride()}, src.data(), base);
250 } else {
251 a = array({src.rows(), src.cols()},
252 {elem_size * src.rowStride(), elem_size * src.colStride()},
253 src.data(),
254 base);
255 }
256
257 if (!writeable) {
259 }
260
261 return a.release();
262}
263
264// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that
265// reference the Eigen object's data with `base` as the python-registered base class (if omitted,
266// the base will be set to None, and lifetime management is up to the caller). The numpy array is
267// non-writeable if the given type is const.
268template <typename props, typename Type>
269handle eigen_ref_array(Type &src, handle parent = none()) {
270 // none here is to get past array's should-we-copy detection, which currently always
271 // copies when there is no base. Setting the base to None should be harmless.
272 return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
273}
274
275// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a
276// numpy array that references the encapsulated data with a python-side reference to the capsule to
277// tie its destruction to that of any dependent python objects. Const-ness is determined by
278// whether or not the Type of the pointer given is const.
279template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
281 capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
282 return eigen_ref_array<props>(*src, base);
283}
284
285// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense
286// types.
287template <typename Type>
289 using Scalar = typename Type::Scalar;
291
292 bool load(handle src, bool convert) {
293 // If we're in no-convert mode, only load if given an array of the correct type
294 if (!convert && !isinstance<array_t<Scalar>>(src)) {
295 return false;
296 }
297
298 // Coerce into an array, but don't do type conversion yet; the copy below handles it.
299 auto buf = array::ensure(src);
300
301 if (!buf) {
302 return false;
303 }
304
305 auto dims = buf.ndim();
306 if (dims < 1 || dims > 2) {
307 return false;
308 }
309
310 auto fits = props::conformable(buf);
311 if (!fits) {
312 return false;
313 }
314
315 // Allocate the new type, then build a numpy reference into it
316 value = Type(fits.rows, fits.cols);
317 auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
318 if (dims == 1) {
319 ref = ref.squeeze();
320 } else if (ref.ndim() == 1) {
321 buf = buf.squeeze();
322 }
323
324 int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
325
326 if (result < 0) { // Copy failed!
327 PyErr_Clear();
328 return false;
329 }
330
331 return true;
332 }
333
334private:
335 // Cast implementation
336 template <typename CType>
337 static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
338 switch (policy) {
339 case return_value_policy::take_ownership:
340 case return_value_policy::automatic:
341 return eigen_encapsulate<props>(src);
342 case return_value_policy::move:
343 return eigen_encapsulate<props>(new CType(std::move(*src)));
344 case return_value_policy::copy:
345 return eigen_array_cast<props>(*src);
346 case return_value_policy::reference:
347 case return_value_policy::automatic_reference:
348 return eigen_ref_array<props>(*src);
349 case return_value_policy::reference_internal:
350 return eigen_ref_array<props>(*src, parent);
351 default:
352 throw cast_error("unhandled return_value_policy: should not happen!");
353 };
354 }
355
356public:
357 // Normal returned non-reference, non-const value:
358 static handle cast(Type &&src, return_value_policy /* policy */, handle parent) {
359 return cast_impl(&src, return_value_policy::move, parent);
360 }
361 // If you return a non-reference const, we mark the numpy array readonly:
362 static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) {
363 return cast_impl(&src, return_value_policy::move, parent);
364 }
365 // lvalue reference return; default (automatic) becomes copy
366 static handle cast(Type &src, return_value_policy policy, handle parent) {
367 if (policy == return_value_policy::automatic
368 || policy == return_value_policy::automatic_reference) {
369 policy = return_value_policy::copy;
370 }
371 return cast_impl(&src, policy, parent);
372 }
373 // const lvalue reference return; default (automatic) becomes copy
374 static handle cast(const Type &src, return_value_policy policy, handle parent) {
375 if (policy == return_value_policy::automatic
376 || policy == return_value_policy::automatic_reference) {
377 policy = return_value_policy::copy;
378 }
379 return cast(&src, policy, parent);
380 }
381 // non-const pointer return
382 static handle cast(Type *src, return_value_policy policy, handle parent) {
383 return cast_impl(src, policy, parent);
384 }
385 // const pointer return
386 static handle cast(const Type *src, return_value_policy policy, handle parent) {
387 return cast_impl(src, policy, parent);
388 }
389
390 static constexpr auto name = props::descriptor;
391
392 // NOLINTNEXTLINE(google-explicit-constructor)
393 operator Type *() { return &value; }
394 // NOLINTNEXTLINE(google-explicit-constructor)
395 operator Type &() { return value; }
396 // NOLINTNEXTLINE(google-explicit-constructor)
397 operator Type &&() && { return std::move(value); }
398 template <typename T>
400
401private:
402 Type value;
403};
404
405// Base class for casting reference/map/block/etc. objects back to python.
406template <typename MapType>
407struct eigen_map_caster {
408private:
410
411public:
412 // Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has
413 // to stay around), but we'll allow it under the assumption that you know what you're doing
414 // (and have an appropriate keep_alive in place). We return a numpy array pointing directly at
415 // the ref's data (The numpy array ends up read-only if the ref was to a const matrix type.)
416 // Note that this means you need to ensure you don't destroy the object in some other way (e.g.
417 // with an appropriate keep_alive, or with a reference to a statically allocated matrix).
418 static handle cast(const MapType &src, return_value_policy policy, handle parent) {
419 switch (policy) {
420 case return_value_policy::copy:
421 return eigen_array_cast<props>(src);
422 case return_value_policy::reference_internal:
423 return eigen_array_cast<props>(src, parent, is_eigen_mutable_map<MapType>::value);
424 case return_value_policy::reference:
425 case return_value_policy::automatic:
426 case return_value_policy::automatic_reference:
427 return eigen_array_cast<props>(src, none(), is_eigen_mutable_map<MapType>::value);
428 default:
429 // move, take_ownership don't make any sense for a ref/map:
430 pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type");
431 }
432 }
433
434 static constexpr auto name = props::descriptor;
435
436 // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
437 // types but not bound arguments). We still provide them (with an explicitly delete) so that
438 // you end up here if you try anyway.
439 bool load(handle, bool) = delete;
440 operator MapType() = delete;
441 template <typename>
442 using cast_op_type = MapType;
443};
444
445// We can return any map-like object (but can only load Refs, specialized next):
446template <typename Type>
447struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>> : eigen_map_caster<Type> {};
448
449// Loader for Ref<...> arguments. See the documentation for info on how to make this work without
450// copying (it requires some extra effort in many cases).
451template <typename PlainObjectType, typename StrideType>
452struct type_caster<
453 Eigen::Ref<PlainObjectType, 0, StrideType>,
454 enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>>
455 : public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
456private:
457 using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
459 using Scalar = typename props::Scalar;
460 using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
461 using Array
462 = array_t<Scalar,
464 | ((props::row_major ? props::inner_stride : props::outer_stride) == 1
466 : (props::row_major ? props::outer_stride : props::inner_stride) == 1
468 : 0)>;
469 static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
470 // Delay construction (these have no default constructor)
471 std::unique_ptr<MapType> map;
472 std::unique_ptr<Type> ref;
473 // Our array. When possible, this is just a numpy array pointing to the source data, but
474 // sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an
475 // incompatible layout, or is an array of a type that needs to be converted). Using a numpy
476 // temporary (rather than an Eigen temporary) saves an extra copy when we need both type
477 // conversion and storage order conversion. (Note that we refuse to use this temporary copy
478 // when loading an argument for a Ref<M> with M non-const, i.e. a read-write reference).
479 Array copy_or_ref;
480
481public:
482 bool load(handle src, bool convert) {
483 // First check whether what we have is already an array of the right type. If not, we
484 // can't avoid a copy (because the copy is also going to do type conversion).
485 bool need_copy = !isinstance<Array>(src);
486
488 if (!need_copy) {
489 // We don't need a converting copy, but we also need to check whether the strides are
490 // compatible with the Ref's stride requirements
491 auto aref = reinterpret_borrow<Array>(src);
492
493 if (aref && (!need_writeable || aref.writeable())) {
494 fits = props::conformable(aref);
495 if (!fits) {
496 return false; // Incompatible dimensions
497 }
498 if (!fits.template stride_compatible<props>()) {
499 need_copy = true;
500 } else {
501 copy_or_ref = std::move(aref);
502 }
503 } else {
504 need_copy = true;
505 }
506 }
507
508 if (need_copy) {
509 // We need to copy: If we need a mutable reference, or we're not supposed to convert
510 // (either because we're in the no-convert overload pass, or because we're explicitly
511 // instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.
512 if (!convert || need_writeable) {
513 return false;
514 }
515
516 Array copy = Array::ensure(src);
517 if (!copy) {
518 return false;
519 }
520 fits = props::conformable(copy);
521 if (!fits || !fits.template stride_compatible<props>()) {
522 return false;
523 }
524 copy_or_ref = std::move(copy);
526 }
527
528 ref.reset();
529 map.reset(new MapType(data(copy_or_ref),
530 fits.rows,
531 fits.cols,
532 make_stride(fits.stride.outer(), fits.stride.inner())));
533 ref.reset(new Type(*map));
534
535 return true;
536 }
537
538 // NOLINTNEXTLINE(google-explicit-constructor)
539 operator Type *() { return ref.get(); }
540 // NOLINTNEXTLINE(google-explicit-constructor)
541 operator Type &() { return *ref; }
542 template <typename _T>
543 using cast_op_type = pybind11::detail::cast_op_type<_T>;
544
545private:
546 template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
548 return a.mutable_data();
549 }
550
551 template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
552 const Scalar *data(Array &a) {
553 return a.data();
554 }
555
556 // Attempt to figure out a constructor of `Stride` that will work.
557 // If both strides are fixed, use a default constructor:
558 template <typename S>
559 using stride_ctor_default = bool_constant<S::InnerStrideAtCompileTime != Eigen::Dynamic
560 && S::OuterStrideAtCompileTime != Eigen::Dynamic
561 && std::is_default_constructible<S>::value>;
562 // Otherwise, if there is a two-index constructor, assume it is (outer,inner) like
563 // Eigen::Stride, and use it:
564 template <typename S>
567 && std::is_constructible<S, EigenIndex, EigenIndex>::value>;
568 // Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use
569 // it (passing whichever stride is dynamic).
570 template <typename S>
573 && S::OuterStrideAtCompileTime == Eigen::Dynamic
574 && S::InnerStrideAtCompileTime != Eigen::Dynamic
575 && std::is_constructible<S, EigenIndex>::value>;
576 template <typename S>
579 && S::InnerStrideAtCompileTime == Eigen::Dynamic
580 && S::OuterStrideAtCompileTime != Eigen::Dynamic
581 && std::is_constructible<S, EigenIndex>::value>;
582
583 template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
585 return S();
586 }
587 template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
588 static S make_stride(EigenIndex outer, EigenIndex inner) {
589 return S(outer, inner);
590 }
591 template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
593 return S(outer);
594 }
595 template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
597 return S(inner);
598 }
599};
600
601// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not
602// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout).
603// load() is not supported, but we can cast them into the python domain by first copying to a
604// regular Eigen::Matrix, then casting that.
605template <typename Type>
607protected:
608 using Matrix
609 = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
611
612public:
613 static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
614 handle h = eigen_encapsulate<props>(new Matrix(src));
615 return h;
616 }
617 static handle cast(const Type *src, return_value_policy policy, handle parent) {
618 return cast(*src, policy, parent);
619 }
620
621 static constexpr auto name = props::descriptor;
622
623 // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
624 // types but not bound arguments). We still provide them (with an explicitly delete) so that
625 // you end up here if you try anyway.
626 bool load(handle, bool) = delete;
627 operator Type() = delete;
628 template <typename>
629 using cast_op_type = Type;
630};
631
632template <typename Type>
633struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
634 using Scalar = typename Type::Scalar;
636 using Index = typename Type::Index;
637 static constexpr bool rowMajor = Type::IsRowMajor;
638
639 bool load(handle src, bool) {
640 if (!src) {
641 return false;
642 }
643
644 auto obj = reinterpret_borrow<object>(src);
645 object sparse_module = module_::import("scipy.sparse");
646 object matrix_type = sparse_module.attr(rowMajor ? "csr_matrix" : "csc_matrix");
647
648 if (!type::handle_of(obj).is(matrix_type)) {
649 try {
650 obj = matrix_type(obj);
651 } catch (const error_already_set &) {
652 return false;
653 }
654 }
655
656 auto values = array_t<Scalar>((object) obj.attr("data"));
657 auto innerIndices = array_t<StorageIndex>((object) obj.attr("indices"));
658 auto outerIndices = array_t<StorageIndex>((object) obj.attr("indptr"));
659 auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
660 auto nnz = obj.attr("nnz").cast<Index>();
661
662 if (!values || !innerIndices || !outerIndices) {
663 return false;
664 }
665
667 Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),
668 StorageIndex>(shape[0].cast<Index>(),
669 shape[1].cast<Index>(),
670 std::move(nnz),
671 outerIndices.mutable_data(),
672 innerIndices.mutable_data(),
673 values.mutable_data());
674
675 return true;
676 }
677
678 static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
679 const_cast<Type &>(src).makeCompressed();
680
681 object matrix_type
682 = module_::import("scipy.sparse").attr(rowMajor ? "csr_matrix" : "csc_matrix");
683
684 array data(src.nonZeros(), src.valuePtr());
685 array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
686 array innerIndices(src.nonZeros(), src.innerIndexPtr());
687
688 return matrix_type(pybind11::make_tuple(
689 std::move(data), std::move(innerIndices), std::move(outerIndices)),
690 pybind11::make_tuple(src.rows(), src.cols()))
691 .release();
692 }
693
695 const_name<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[",
696 "scipy.sparse.csc_matrix[")
698};
699
Definition: numpy.h:991
const T * data(Ix... index) const
Definition: numpy.h:1055
T * mutable_data(Ix... index)
Definition: numpy.h:1060
Definition: numpy.h:655
ssize_t ndim() const
Number of dimensions.
Definition: numpy.h:770
const ssize_t * strides() const
Strides of the array.
Definition: numpy.h:787
static array ensure(handle h, int ExtraFlags=0)
Ensure that the argument is a NumPy array In case of an error, nullptr is returned and the Python err...
Definition: numpy.h:933
@ forcecast
Definition: numpy.h:662
@ c_style
Definition: numpy.h:660
@ f_style
Definition: numpy.h:661
const ssize_t * shape() const
Dimensions of the array.
Definition: numpy.h:776
Fetch and hold an error which was already set in Python.
Definition: pytypes.h:379
\rst Holds a reference to a Python object (no reference counting)
Definition: pytypes.h:194
PyObject * ptr() const
Return the underlying PyObject * pointer.
Definition: pytypes.h:203
static PYBIND11_NOINLINE void add_patient(handle h)
This can only be used inside a pybind11-bound function, either by argument_loader at argument prepara...
static module_ import(const char *name)
Import and return a module or throws error_already_set.
Definition: pybind11.h:1200
Definition: pytypes.h:1422
handle release()
\rst Resets the internal pointer to nullptr without decreasing the object's reference count.
Definition: pytypes.h:283
Reference counting helper.
Definition: object.h:67
static handle cast(const itype &src, return_value_policy policy, handle parent)
Definition: pytypes.h:1167
static handle handle_of()
Convert C++ type to handle if previously registered.
Definition: cast.h:1643
bool isinstance(handle obj)
\rst Return true if obj is an instance of T.
Definition: pytypes.h:489
handle eigen_array_cast(typename props::Type const &src, handle base=handle(), bool writeable=true)
Definition: matrix.h:245
handle eigen_ref_array(Type &src, handle parent=none())
Definition: matrix.h:269
EIGEN_DEFAULT_DENSE_INDEX_TYPE EigenIndex
Definition: matrix.h:55
handle eigen_encapsulate(Type *src)
Definition: matrix.h:280
std::is_base_of< Eigen::MapBase< T, Eigen::WriteAccessors >, T > is_eigen_mutable_map
Definition: matrix.h:65
Eigen::MappedSparseMatrix< Scalar, Flags, StorageIndex > EigenMapSparseMatrix
Definition: matrix.h:57
PYBIND11_WARNING_PUSH PYBIND11_WARNING_POP
Definition: matrix.h:35
_Type< T > Type()
typename std::enable_if< B, T >::type enable_if_t
from cpp_future import (convenient aliases from C++14/17)
Definition: common.h:625
std::integral_constant< bool, B > bool_constant
Backports of std::bool_constant and std::negation to accommodate older compilers.
Definition: common.h:678
PYBIND11_NOINLINE void pybind11_fail(const char *reason)
Thrown when pybind11::cast or.
Definition: common.h:992
typename std::remove_reference< T >::type remove_reference_t
Definition: common.h:631
decltype(is_template_base_of_impl< Base >::check((intrinsic_t< T > *) nullptr)) is_template_base_of
Check if a template is the base of a type.
Definition: common.h:883
#define PYBIND11_NAMESPACE_END(name)
Definition: common.h:21
#define PYBIND11_NAMESPACE_BEGIN(name)
Definition: common.h:20
Py_ssize_t ssize_t
Definition: common.h:460
std::is_same< bools< Ts::value..., true >, bools< true, Ts::value... > > all_of
Definition: common.h:707
return_value_policy
Approach used to cast a previously unknown C++ instance into a Python object.
Definition: common.h:470
@ copy
Create a new copy of the returned object, which will be owned by Python.
constexpr descr< N - 1 > const_name(char const (&text)[N])
Definition: descr.h:60
conditional_t< std::is_pointer< typename std::remove_reference< T >::type >::value, typename std::add_pointer< intrinsic_t< T > >::type, conditional_t< std::is_rvalue_reference< T >::value, typename std::add_rvalue_reference< intrinsic_t< T > >::type, typename std::add_lvalue_reference< intrinsic_t< T > >::type > > movable_cast_op_type
Determine suitable casting operator for a type caster with a movable value.
all_of< is_template_base_of< Eigen::DenseBase, T >, std::is_base_of< Eigen::MapBase< T, Eigen::ReadOnlyAccessors >, T > > is_eigen_dense_map
Definition: eigen.h:67
Eigen::Map< MatrixType, 0, EigenDStride > EigenDMap
Definition: eigen.h:50
EIGEN_DEFAULT_DENSE_INDEX_TYPE EigenIndex
Definition: eigen.h:59
Eigen::Stride< Eigen::Dynamic, Eigen::Dynamic > EigenDStride
Definition: eigen.h:46
all_of< negation< is_eigen_dense_map< T > >, is_template_base_of< Eigen::PlainObjectBase, T > > is_eigen_dense_plain
Definition: eigen.h:72
std::is_base_of< Eigen::MapBase< T, Eigen::WriteAccessors >, T > is_eigen_mutable_map
Definition: eigen.h:69
Eigen::Ref< MatrixType, 0, EigenDStride > EigenDRef
Definition: eigen.h:48
Eigen::MappedSparseMatrix< Scalar, Flags, StorageIndex > EigenMapSparseMatrix
Definition: eigen.h:61
all_of< is_template_base_of< Eigen::EigenBase, T >, negation< any_of< is_eigen_dense_map< T >, is_eigen_dense_plain< T >, is_eigen_sparse< T > > > > is_eigen_other
Definition: eigen.h:82
is_template_base_of< Eigen::SparseMatrixBase, T > is_eigen_sparse
Definition: eigen.h:74
PyArray_Proxy * array_proxy(void *ptr)
Definition: numpy.h:301
arr data(const arr &a, Ix... index)
#define PYBIND11_WARNING_DISABLE_GCC(name)
Definition: common.h:67
#define PYBIND11_WARNING_DISABLE_MSVC(name)
Definition: common.h:55
bool conformable
Definition: eigen.h:87
EigenConformable(bool fits=false)
Definition: matrix.h:89
EigenIndex rows
Definition: eigen.h:88
EigenConformable(EigenIndex r, EigenIndex c, EigenIndex rstride, EigenIndex cstride)
Definition: matrix.h:91
EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)
Definition: matrix.h:101
bool stride_compatible() const
Definition: matrix.h:105
EigenIndex cols
Definition: eigen.h:88
EigenDStride stride
Definition: eigen.h:89
bool negativestrides
Definition: eigen.h:90
static constexpr bool fixed
Definition: eigen.h:148
static constexpr EigenIndex rows
Definition: eigen.h:142
static constexpr bool dynamic_stride
Definition: eigen.h:160
typename eigen_extract_stride< Type >::type StrideType
Definition: eigen.h:141
static constexpr bool show_writeable
Definition: eigen.h:218
static constexpr bool requires_row_major
Definition: eigen.h:162
static constexpr bool show_c_contiguous
Definition: eigen.h:220
static EigenConformable< row_major > conformable(const array &a)
Definition: matrix.h:171
static constexpr EigenIndex outer_stride
Definition: eigen.h:155
static constexpr bool row_major
Definition: eigen.h:144
static constexpr EigenIndex size
Definition: eigen.h:143
static constexpr bool vector
Definition: eigen.h:146
static constexpr bool fixed_rows
Definition: eigen.h:147
static constexpr bool show_order
Definition: eigen.h:219
static constexpr EigenIndex inner_stride
Definition: eigen.h:154
static constexpr auto descriptor
Definition: eigen.h:225
std::integral_constant< EigenIndex, i==0 ? ifzero :i > if_zero
Definition: eigen.h:152
static constexpr bool show_f_contiguous
Definition: eigen.h:222
Type_ Type
Definition: eigen.h:139
static constexpr bool fixed_cols
Definition: eigen.h:147
static constexpr bool dynamic
Definition: eigen.h:149
typename Type::Scalar Scalar
Definition: eigen.h:140
static constexpr EigenIndex cols
Definition: eigen.h:142
static constexpr bool requires_col_major
Definition: eigen.h:164
int flags
Definition: numpy.h:74
Annotation indicating that a class derives from another given type.
Definition: attr.h:60
MapType cast_op_type
Definition: eigen.h:441
bool load(handle, bool)=delete
static handle cast(const MapType &src, return_value_policy policy, handle parent)
Definition: matrix.h:418
Annotation for function names.
Definition: attr.h:47
@ NPY_ARRAY_WRITEABLE_
Definition: numpy.h:146
bool_constant<!any_of< stride_ctor_default< S >, stride_ctor_dual< S > >::value &&S::InnerStrideAtCompileTime==Eigen::Dynamic &&S::OuterStrideAtCompileTime !=Eigen::Dynamic &&std::is_constructible< S, EigenIndex >::value > stride_ctor_inner
Definition: eigen.h:580
bool_constant<!stride_ctor_default< S >::value &&std::is_constructible< S, EigenIndex, EigenIndex >::value > stride_ctor_dual
Definition: eigen.h:566
bool_constant<!any_of< stride_ctor_default< S >, stride_ctor_dual< S > >::value &&S::OuterStrideAtCompileTime==Eigen::Dynamic &&S::InnerStrideAtCompileTime !=Eigen::Dynamic &&std::is_constructible< S, EigenIndex >::value > stride_ctor_outer
Definition: eigen.h:574
bool_constant< S::InnerStrideAtCompileTime !=Eigen::Dynamic &&S::OuterStrideAtCompileTime !=Eigen::Dynamic &&std::is_default_constructible< S >::value > stride_ctor_default
Definition: eigen.h:560
static handle cast(Type &src, return_value_policy policy, handle parent)
Definition: matrix.h:366
static handle cast(Type *src, return_value_policy policy, handle parent)
Definition: matrix.h:382
static handle cast(const Type &src, return_value_policy policy, handle parent)
Definition: matrix.h:374
static handle cast(Type &&src, return_value_policy, handle parent)
Definition: matrix.h:358
static handle cast_impl(CType *src, return_value_policy policy, handle parent)
Definition: matrix.h:337
static handle cast(const Type *src, return_value_policy policy, handle parent)
Definition: matrix.h:386
static handle cast(const Type &&src, return_value_policy, handle parent)
Definition: matrix.h:362
Eigen::Matrix< typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime > Matrix
Definition: eigen.h:608
static handle cast(const Type *src, return_value_policy policy, handle parent)
Definition: matrix.h:617
static handle cast(const Type &src, return_value_policy, handle)
Definition: matrix.h:613
static handle cast(const Type &src, return_value_policy, handle)
Definition: matrix.h:678
remove_reference_t< decltype(*std::declval< Type >().outerIndexPtr())> StorageIndex
Definition: eigen.h:634
PYBIND11_TYPE_CASTER(Type, const_name<(Type::IsRowMajor) !=0 >("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[")+npy_format_descriptor< Scalar >::name+const_name("]"))