File indexing completed on 2026-01-04 09:52:04
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #pragma once
0011
0012 #include <pybind11/numpy.h>
0013
0014 #include "common.h"
0015
0016
0017
0018
0019
0020
0021 PYBIND11_WARNING_PUSH
0022 PYBIND11_WARNING_DISABLE_MSVC(5054)
0023
0024 #if defined(__MINGW32__)
0025 PYBIND11_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
0026 #endif
0027
0028 #include <Eigen/Core>
0029 #include <Eigen/SparseCore>
0030
0031 PYBIND11_WARNING_POP
0032
0033
0034
0035
0036 static_assert(EIGEN_VERSION_AT_LEAST(3, 2, 7),
0037 "Eigen matrix support in pybind11 requires Eigen >= 3.2.7");
0038
0039 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
0040
0041 PYBIND11_WARNING_DISABLE_MSVC(4127)
0042
0043
0044 using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
0045 template <typename MatrixType>
0046 using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
0047 template <typename MatrixType>
0048 using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
0049
0050 PYBIND11_NAMESPACE_BEGIN(detail)
0051
0052 #if EIGEN_VERSION_AT_LEAST(3, 3, 0)
0053 using EigenIndex = Eigen::Index;
0054 template <typename Scalar, int Flags, typename StorageIndex>
0055 using EigenMapSparseMatrix = Eigen::Map<Eigen::SparseMatrix<Scalar, Flags, StorageIndex>>;
0056 #else
0057 using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
0058 template <typename Scalar, int Flags, typename StorageIndex>
0059 using EigenMapSparseMatrix = Eigen::MappedSparseMatrix<Scalar, Flags, StorageIndex>;
0060 #endif
0061
0062
0063 template <typename T>
0064 using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>,
0065 std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
0066 template <typename T>
0067 using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
0068 template <typename T>
0069 using is_eigen_dense_plain
0070 = all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
0071 template <typename T>
0072 using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
0073
0074
0075
0076
0077 template <typename T>
0078 using is_eigen_other
0079 = all_of<is_template_base_of<Eigen::EigenBase, T>,
0080 negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>>;
0081
0082
0083 template <bool EigenRowMajor>
0084 struct EigenConformable {
0085 bool conformable = false;
0086 EigenIndex rows = 0, cols = 0;
0087 EigenDStride stride{0, 0};
0088 bool negativestrides = false;
0089
0090
0091 EigenConformable(bool fits = false) : conformable{fits} {}
0092
0093 EigenConformable(EigenIndex r, EigenIndex c, EigenIndex rstride, EigenIndex cstride)
0094 : conformable{true}, rows{r}, cols{c},
0095
0096
0097 stride{EigenRowMajor ? (rstride > 0 ? rstride : 0)
0098 : (cstride > 0 ? cstride : 0) ,
0099 EigenRowMajor ? (cstride > 0 ? cstride : 0)
0100 : (rstride > 0 ? rstride : 0) },
0101 negativestrides{rstride < 0 || cstride < 0} {}
0102
0103 EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)
0104 : EigenConformable(r, c, r == 1 ? c * stride : stride, c == 1 ? r : r * stride) {}
0105
0106 template <typename props>
0107 bool stride_compatible() const {
0108
0109
0110
0111
0112 if (negativestrides) {
0113 return false;
0114 }
0115 if (rows == 0 || cols == 0) {
0116 return true;
0117 }
0118 return (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner()
0119 || (EigenRowMajor ? cols : rows) == 1)
0120 && (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer()
0121 || (EigenRowMajor ? rows : cols) == 1);
0122 }
0123
0124 operator bool() const { return conformable; }
0125 };
0126
0127 template <typename Type>
0128 struct eigen_extract_stride {
0129 using type = Type;
0130 };
0131 template <typename PlainObjectType, int MapOptions, typename StrideType>
0132 struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> {
0133 using type = StrideType;
0134 };
0135 template <typename PlainObjectType, int Options, typename StrideType>
0136 struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> {
0137 using type = StrideType;
0138 };
0139
0140
0141 template <typename Type_>
0142 struct EigenProps {
0143 using Type = Type_;
0144 using Scalar = typename Type::Scalar;
0145 using StrideType = typename eigen_extract_stride<Type>::type;
0146 static constexpr EigenIndex rows = Type::RowsAtCompileTime, cols = Type::ColsAtCompileTime,
0147 size = Type::SizeAtCompileTime;
0148 static constexpr bool row_major = Type::IsRowMajor,
0149 vector
0150 = Type::IsVectorAtCompileTime,
0151 fixed_rows = rows != Eigen::Dynamic, fixed_cols = cols != Eigen::Dynamic,
0152 fixed = size != Eigen::Dynamic,
0153 dynamic = !fixed_rows && !fixed_cols;
0154
0155 template <EigenIndex i, EigenIndex ifzero>
0156 using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
0157 static constexpr EigenIndex inner_stride
0158 = if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
0159 outer_stride = if_zero < StrideType::OuterStrideAtCompileTime,
0160 vector ? size
0161 : row_major ? cols
0162 : rows > ::value;
0163 static constexpr bool dynamic_stride
0164 = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
0165 static constexpr bool requires_row_major
0166 = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
0167 static constexpr bool requires_col_major
0168 = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
0169
0170
0171
0172
0173 static EigenConformable<row_major> conformable(const array &a) {
0174 const auto dims = a.ndim();
0175 if (dims < 1 || dims > 2) {
0176 return false;
0177 }
0178
0179 if (dims == 2) {
0180
0181 EigenIndex np_rows = a.shape(0), np_cols = a.shape(1),
0182 np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),
0183 np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));
0184 if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols)) {
0185 return false;
0186 }
0187
0188 return {np_rows, np_cols, np_rstride, np_cstride};
0189 }
0190
0191
0192
0193 const EigenIndex n = a.shape(0),
0194 stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));
0195
0196 if (vector) {
0197 if (fixed && size != n) {
0198 return false;
0199 }
0200 return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
0201 }
0202 if (fixed) {
0203
0204 return false;
0205 }
0206 if (fixed_cols) {
0207
0208
0209 if (cols != n) {
0210 return false;
0211 }
0212 return {1, n, stride};
0213 }
0214 if (fixed_rows && rows != n) {
0215 return false;
0216 }
0217 return {n, 1, stride};
0218 }
0219
0220 static constexpr bool show_writeable
0221 = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
0222 static constexpr bool show_order = is_eigen_dense_map<Type>::value;
0223 static constexpr bool show_c_contiguous = show_order && requires_row_major;
0224 static constexpr bool show_f_contiguous
0225 = !show_c_contiguous && show_order && requires_col_major;
0226
0227 static constexpr auto descriptor
0228 = const_name("typing.Annotated[")
0229 + io_name("numpy.typing.ArrayLike, ", "numpy.typing.NDArray[")
0230 + npy_format_descriptor<Scalar>::name + io_name("", "]") + const_name(", \"[")
0231 + const_name<fixed_rows>(const_name<(size_t) rows>(), const_name("m")) + const_name(", ")
0232 + const_name<fixed_cols>(const_name<(size_t) cols>(), const_name("n"))
0233 + const_name("]\"")
0234
0235
0236
0237
0238
0239
0240
0241 + const_name<show_writeable>(", \"flags.writeable\"", "")
0242 + const_name<show_c_contiguous>(", \"flags.c_contiguous\"", "")
0243 + const_name<show_f_contiguous>(", \"flags.f_contiguous\"", "") + const_name("]");
0244 };
0245
0246
0247
0248 template <typename props>
0249 handle
0250 eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
0251 constexpr ssize_t elem_size = sizeof(typename props::Scalar);
0252 array a;
0253 if (props::vector) {
0254 a = array({src.size()}, {elem_size * src.innerStride()}, src.data(), base);
0255 } else {
0256 a = array({src.rows(), src.cols()},
0257 {elem_size * src.rowStride(), elem_size * src.colStride()},
0258 src.data(),
0259 base);
0260 }
0261
0262 if (!writeable) {
0263 array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
0264 }
0265
0266 return a.release();
0267 }
0268
0269
0270
0271
0272
0273 template <typename props, typename Type>
0274 handle eigen_ref_array(Type &src, handle parent = none()) {
0275
0276
0277 return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
0278 }
0279
0280
0281
0282
0283
0284 template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
0285 handle eigen_encapsulate(Type *src) {
0286 capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
0287 return eigen_ref_array<props>(*src, base);
0288 }
0289
0290
0291
0292 template <typename Type>
0293 struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
0294 using Scalar = typename Type::Scalar;
0295 static_assert(!std::is_pointer<Scalar>::value,
0296 PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
0297 using props = EigenProps<Type>;
0298
0299 bool load(handle src, bool convert) {
0300
0301 if (!convert && !isinstance<array_t<Scalar>>(src)) {
0302 return false;
0303 }
0304
0305
0306 auto buf = array::ensure(src);
0307
0308 if (!buf) {
0309 return false;
0310 }
0311
0312 auto dims = buf.ndim();
0313 if (dims < 1 || dims > 2) {
0314 return false;
0315 }
0316
0317 auto fits = props::conformable(buf);
0318 if (!fits) {
0319 return false;
0320 }
0321
0322 PYBIND11_WARNING_PUSH
0323 PYBIND11_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
0324
0325 value = Type(fits.rows, fits.cols);
0326 PYBIND11_WARNING_POP
0327 auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
0328 if (dims == 1) {
0329 ref = ref.squeeze();
0330 } else if (ref.ndim() == 1) {
0331 buf = buf.squeeze();
0332 }
0333
0334 int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
0335
0336 if (result < 0) {
0337 PyErr_Clear();
0338 return false;
0339 }
0340
0341 return true;
0342 }
0343
0344 private:
0345
0346 template <typename CType>
0347 static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
0348 switch (policy) {
0349 case return_value_policy::take_ownership:
0350 case return_value_policy::automatic:
0351 return eigen_encapsulate<props>(src);
0352 case return_value_policy::move:
0353 return eigen_encapsulate<props>(new CType(std::move(*src)));
0354 case return_value_policy::copy:
0355 return eigen_array_cast<props>(*src);
0356 case return_value_policy::reference:
0357 case return_value_policy::automatic_reference:
0358 return eigen_ref_array<props>(*src);
0359 case return_value_policy::reference_internal:
0360 return eigen_ref_array<props>(*src, parent);
0361 default:
0362 throw cast_error("unhandled return_value_policy: should not happen!");
0363 };
0364 }
0365
0366 public:
0367
0368 static handle cast(Type &&src, return_value_policy , handle parent) {
0369 return cast_impl(&src, return_value_policy::move, parent);
0370 }
0371
0372 static handle cast(const Type &&src, return_value_policy , handle parent) {
0373 return cast_impl(&src, return_value_policy::move, parent);
0374 }
0375
0376 static handle cast(Type &src, return_value_policy policy, handle parent) {
0377 if (policy == return_value_policy::automatic
0378 || policy == return_value_policy::automatic_reference) {
0379 policy = return_value_policy::copy;
0380 }
0381 return cast_impl(&src, policy, parent);
0382 }
0383
0384 static handle cast(const Type &src, return_value_policy policy, handle parent) {
0385 if (policy == return_value_policy::automatic
0386 || policy == return_value_policy::automatic_reference) {
0387 policy = return_value_policy::copy;
0388 }
0389 return cast(&src, policy, parent);
0390 }
0391
0392 static handle cast(Type *src, return_value_policy policy, handle parent) {
0393 return cast_impl(src, policy, parent);
0394 }
0395
0396 static handle cast(const Type *src, return_value_policy policy, handle parent) {
0397 return cast_impl(src, policy, parent);
0398 }
0399
0400 static constexpr auto name = props::descriptor;
0401
0402
0403 operator Type *() { return &value; }
0404
0405 operator Type &() { return value; }
0406
0407 operator Type &&() && { return std::move(value); }
0408 template <typename T>
0409 using cast_op_type = movable_cast_op_type<T>;
0410
0411 private:
0412 Type value;
0413 };
0414
0415
0416 template <typename MapType>
0417 struct eigen_map_caster {
0418 static_assert(!std::is_pointer<typename MapType::Scalar>::value,
0419 PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
0420
0421 private:
0422 using props = EigenProps<MapType>;
0423
0424 public:
0425
0426
0427
0428
0429
0430
0431 static handle cast(const MapType &src, return_value_policy policy, handle parent) {
0432 switch (policy) {
0433 case return_value_policy::copy:
0434 return eigen_array_cast<props>(src);
0435 case return_value_policy::reference_internal:
0436 return eigen_array_cast<props>(src, parent, is_eigen_mutable_map<MapType>::value);
0437 case return_value_policy::reference:
0438 case return_value_policy::automatic:
0439 case return_value_policy::automatic_reference:
0440 return eigen_array_cast<props>(src, none(), is_eigen_mutable_map<MapType>::value);
0441 default:
0442
0443 pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type");
0444 }
0445 }
0446
0447
0448
0449 static constexpr auto name = return_descr(props::descriptor);
0450
0451
0452
0453
0454 bool load(handle, bool) = delete;
0455 operator MapType() = delete;
0456 template <typename>
0457 using cast_op_type = MapType;
0458 };
0459
0460
0461 template <typename Type>
0462 struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>> : eigen_map_caster<Type> {};
0463
0464
0465
0466 template <typename PlainObjectType, typename StrideType>
0467 struct type_caster<
0468 Eigen::Ref<PlainObjectType, 0, StrideType>,
0469 enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>>
0470 : public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
0471 private:
0472 using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
0473 using props = EigenProps<Type>;
0474 using Scalar = typename props::Scalar;
0475 static_assert(!std::is_pointer<Scalar>::value,
0476 PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
0477 using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
0478 using Array
0479 = array_t<Scalar,
0480 array::forcecast
0481 | ((props::row_major ? props::inner_stride : props::outer_stride) == 1
0482 ? array::c_style
0483 : (props::row_major ? props::outer_stride : props::inner_stride) == 1
0484 ? array::f_style
0485 : 0)>;
0486 static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
0487
0488 std::unique_ptr<MapType> map;
0489 std::unique_ptr<Type> ref;
0490
0491
0492
0493
0494
0495
0496 Array copy_or_ref;
0497
0498 public:
0499 bool load(handle src, bool convert) {
0500
0501
0502 bool need_copy = !isinstance<Array>(src);
0503
0504 EigenConformable<props::row_major> fits;
0505 if (!need_copy) {
0506
0507
0508 auto aref = reinterpret_borrow<Array>(src);
0509
0510 if (aref && (!need_writeable || aref.writeable())) {
0511 fits = props::conformable(aref);
0512 if (!fits) {
0513 return false;
0514 }
0515 if (!fits.template stride_compatible<props>()) {
0516 need_copy = true;
0517 } else {
0518 copy_or_ref = std::move(aref);
0519 }
0520 } else {
0521 need_copy = true;
0522 }
0523 }
0524
0525 if (need_copy) {
0526
0527
0528
0529 if (!convert || need_writeable) {
0530 return false;
0531 }
0532
0533 Array copy = Array::ensure(src);
0534 if (!copy) {
0535 return false;
0536 }
0537 fits = props::conformable(copy);
0538 if (!fits || !fits.template stride_compatible<props>()) {
0539 return false;
0540 }
0541 copy_or_ref = std::move(copy);
0542 loader_life_support::add_patient(copy_or_ref);
0543 }
0544
0545 ref.reset();
0546 map.reset(new MapType(data(copy_or_ref),
0547 fits.rows,
0548 fits.cols,
0549 make_stride(fits.stride.outer(), fits.stride.inner())));
0550 ref.reset(new Type(*map));
0551
0552 return true;
0553 }
0554
0555
0556 operator Type *() { return ref.get(); }
0557
0558 operator Type &() { return *ref; }
0559 template <typename _T>
0560 using cast_op_type = pybind11::detail::cast_op_type<_T>;
0561
0562 private:
0563 template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
0564 Scalar *data(Array &a) {
0565 return a.mutable_data();
0566 }
0567
0568 template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
0569 const Scalar *data(Array &a) {
0570 return a.data();
0571 }
0572
0573
0574
0575 template <typename S>
0576 using stride_ctor_default = bool_constant<S::InnerStrideAtCompileTime != Eigen::Dynamic
0577 && S::OuterStrideAtCompileTime != Eigen::Dynamic
0578 && std::is_default_constructible<S>::value>;
0579
0580
0581 template <typename S>
0582 using stride_ctor_dual
0583 = bool_constant<!stride_ctor_default<S>::value
0584 && std::is_constructible<S, EigenIndex, EigenIndex>::value>;
0585
0586
0587 template <typename S>
0588 using stride_ctor_outer
0589 = bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
0590 && S::OuterStrideAtCompileTime == Eigen::Dynamic
0591 && S::InnerStrideAtCompileTime != Eigen::Dynamic
0592 && std::is_constructible<S, EigenIndex>::value>;
0593 template <typename S>
0594 using stride_ctor_inner
0595 = bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
0596 && S::InnerStrideAtCompileTime == Eigen::Dynamic
0597 && S::OuterStrideAtCompileTime != Eigen::Dynamic
0598 && std::is_constructible<S, EigenIndex>::value>;
0599
0600 template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
0601 static S make_stride(EigenIndex, EigenIndex) {
0602 return S();
0603 }
0604 template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
0605 static S make_stride(EigenIndex outer, EigenIndex inner) {
0606 return S(outer, inner);
0607 }
0608 template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
0609 static S make_stride(EigenIndex outer, EigenIndex) {
0610 return S(outer);
0611 }
0612 template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
0613 static S make_stride(EigenIndex, EigenIndex inner) {
0614 return S(inner);
0615 }
0616 };
0617
0618
0619
0620
0621
0622 template <typename Type>
0623 struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
0624 static_assert(!std::is_pointer<typename Type::Scalar>::value,
0625 PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
0626
0627 protected:
0628 using Matrix
0629 = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
0630 using props = EigenProps<Matrix>;
0631
0632 public:
0633 static handle cast(const Type &src, return_value_policy , handle ) {
0634 handle h = eigen_encapsulate<props>(new Matrix(src));
0635 return h;
0636 }
0637 static handle cast(const Type *src, return_value_policy policy, handle parent) {
0638 return cast(*src, policy, parent);
0639 }
0640
0641 static constexpr auto name = props::descriptor;
0642
0643
0644
0645
0646 bool load(handle, bool) = delete;
0647 operator Type() = delete;
0648 template <typename>
0649 using cast_op_type = Type;
0650 };
0651
0652 template <typename Type>
0653 struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
0654 using Scalar = typename Type::Scalar;
0655 static_assert(!std::is_pointer<Scalar>::value,
0656 PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
0657 using StorageIndex = remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())>;
0658 using Index = typename Type::Index;
0659 static constexpr bool rowMajor = Type::IsRowMajor;
0660
0661 bool load(handle src, bool) {
0662 if (!src) {
0663 return false;
0664 }
0665
0666 auto obj = reinterpret_borrow<object>(src);
0667 object sparse_module = module_::import("scipy.sparse");
0668 object matrix_type = sparse_module.attr(rowMajor ? "csr_matrix" : "csc_matrix");
0669
0670 if (!type::handle_of(obj).is(matrix_type)) {
0671 try {
0672 obj = matrix_type(obj);
0673 } catch (const error_already_set &) {
0674 return false;
0675 }
0676 }
0677
0678 auto values = array_t<Scalar>((object) obj.attr("data"));
0679 auto innerIndices = array_t<StorageIndex>((object) obj.attr("indices"));
0680 auto outerIndices = array_t<StorageIndex>((object) obj.attr("indptr"));
0681 auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
0682 auto nnz = obj.attr("nnz").cast<Index>();
0683
0684 if (!values || !innerIndices || !outerIndices) {
0685 return false;
0686 }
0687
0688 value = EigenMapSparseMatrix<Scalar,
0689 Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),
0690 StorageIndex>(shape[0].cast<Index>(),
0691 shape[1].cast<Index>(),
0692 std::move(nnz),
0693 outerIndices.mutable_data(),
0694 innerIndices.mutable_data(),
0695 values.mutable_data());
0696
0697 return true;
0698 }
0699
0700 static handle cast(const Type &src, return_value_policy , handle ) {
0701 const_cast<Type &>(src).makeCompressed();
0702
0703 object matrix_type
0704 = module_::import("scipy.sparse").attr(rowMajor ? "csr_matrix" : "csc_matrix");
0705
0706 array data(src.nonZeros(), src.valuePtr());
0707 array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
0708 array innerIndices(src.nonZeros(), src.innerIndexPtr());
0709
0710 return matrix_type(pybind11::make_tuple(
0711 std::move(data), std::move(innerIndices), std::move(outerIndices)),
0712 pybind11::make_tuple(src.rows(), src.cols()))
0713 .release();
0714 }
0715
0716 PYBIND11_TYPE_CASTER(Type,
0717 const_name<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[",
0718 "scipy.sparse.csc_matrix[")
0719 + npy_format_descriptor<Scalar>::name + const_name("]"));
0720 };
0721
0722 PYBIND11_NAMESPACE_END(detail)
0723 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)