File indexing completed on 2025-01-18 10:06:12
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("numpy.ndarray[") + npy_format_descriptor<Scalar>::name + const_name("[")
0229 + const_name<fixed_rows>(const_name<(size_t) rows>(), const_name("m")) + const_name(", ")
0230 + const_name<fixed_cols>(const_name<(size_t) cols>(), const_name("n")) + const_name("]")
0231 +
0232
0233
0234
0235
0236
0237
0238 const_name<show_writeable>(", flags.writeable", "")
0239 + const_name<show_c_contiguous>(", flags.c_contiguous", "")
0240 + const_name<show_f_contiguous>(", flags.f_contiguous", "") + const_name("]");
0241 };
0242
0243
0244
0245 template <typename props>
0246 handle
0247 eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
0248 constexpr ssize_t elem_size = sizeof(typename props::Scalar);
0249 array a;
0250 if (props::vector) {
0251 a = array({src.size()}, {elem_size * src.innerStride()}, src.data(), base);
0252 } else {
0253 a = array({src.rows(), src.cols()},
0254 {elem_size * src.rowStride(), elem_size * src.colStride()},
0255 src.data(),
0256 base);
0257 }
0258
0259 if (!writeable) {
0260 array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
0261 }
0262
0263 return a.release();
0264 }
0265
0266
0267
0268
0269
0270 template <typename props, typename Type>
0271 handle eigen_ref_array(Type &src, handle parent = none()) {
0272
0273
0274 return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
0275 }
0276
0277
0278
0279
0280
0281 template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
0282 handle eigen_encapsulate(Type *src) {
0283 capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
0284 return eigen_ref_array<props>(*src, base);
0285 }
0286
0287
0288
0289 template <typename Type>
0290 struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
0291 using Scalar = typename Type::Scalar;
0292 static_assert(!std::is_pointer<Scalar>::value,
0293 PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
0294 using props = EigenProps<Type>;
0295
0296 bool load(handle src, bool convert) {
0297
0298 if (!convert && !isinstance<array_t<Scalar>>(src)) {
0299 return false;
0300 }
0301
0302
0303 auto buf = array::ensure(src);
0304
0305 if (!buf) {
0306 return false;
0307 }
0308
0309 auto dims = buf.ndim();
0310 if (dims < 1 || dims > 2) {
0311 return false;
0312 }
0313
0314 auto fits = props::conformable(buf);
0315 if (!fits) {
0316 return false;
0317 }
0318
0319
0320 value = Type(fits.rows, fits.cols);
0321 auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
0322 if (dims == 1) {
0323 ref = ref.squeeze();
0324 } else if (ref.ndim() == 1) {
0325 buf = buf.squeeze();
0326 }
0327
0328 int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
0329
0330 if (result < 0) {
0331 PyErr_Clear();
0332 return false;
0333 }
0334
0335 return true;
0336 }
0337
0338 private:
0339
0340 template <typename CType>
0341 static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
0342 switch (policy) {
0343 case return_value_policy::take_ownership:
0344 case return_value_policy::automatic:
0345 return eigen_encapsulate<props>(src);
0346 case return_value_policy::move:
0347 return eigen_encapsulate<props>(new CType(std::move(*src)));
0348 case return_value_policy::copy:
0349 return eigen_array_cast<props>(*src);
0350 case return_value_policy::reference:
0351 case return_value_policy::automatic_reference:
0352 return eigen_ref_array<props>(*src);
0353 case return_value_policy::reference_internal:
0354 return eigen_ref_array<props>(*src, parent);
0355 default:
0356 throw cast_error("unhandled return_value_policy: should not happen!");
0357 };
0358 }
0359
0360 public:
0361
0362 static handle cast(Type &&src, return_value_policy , handle parent) {
0363 return cast_impl(&src, return_value_policy::move, parent);
0364 }
0365
0366 static handle cast(const Type &&src, return_value_policy , handle parent) {
0367 return cast_impl(&src, return_value_policy::move, parent);
0368 }
0369
0370 static handle cast(Type &src, return_value_policy policy, handle parent) {
0371 if (policy == return_value_policy::automatic
0372 || policy == return_value_policy::automatic_reference) {
0373 policy = return_value_policy::copy;
0374 }
0375 return cast_impl(&src, policy, parent);
0376 }
0377
0378 static handle cast(const Type &src, return_value_policy policy, handle parent) {
0379 if (policy == return_value_policy::automatic
0380 || policy == return_value_policy::automatic_reference) {
0381 policy = return_value_policy::copy;
0382 }
0383 return cast(&src, policy, parent);
0384 }
0385
0386 static handle cast(Type *src, return_value_policy policy, handle parent) {
0387 return cast_impl(src, policy, parent);
0388 }
0389
0390 static handle cast(const Type *src, return_value_policy policy, handle parent) {
0391 return cast_impl(src, policy, parent);
0392 }
0393
0394 static constexpr auto name = props::descriptor;
0395
0396
0397 operator Type *() { return &value; }
0398
0399 operator Type &() { return value; }
0400
0401 operator Type &&() && { return std::move(value); }
0402 template <typename T>
0403 using cast_op_type = movable_cast_op_type<T>;
0404
0405 private:
0406 Type value;
0407 };
0408
0409
0410 template <typename MapType>
0411 struct eigen_map_caster {
0412 static_assert(!std::is_pointer<typename MapType::Scalar>::value,
0413 PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
0414
0415 private:
0416 using props = EigenProps<MapType>;
0417
0418 public:
0419
0420
0421
0422
0423
0424
0425 static handle cast(const MapType &src, return_value_policy policy, handle parent) {
0426 switch (policy) {
0427 case return_value_policy::copy:
0428 return eigen_array_cast<props>(src);
0429 case return_value_policy::reference_internal:
0430 return eigen_array_cast<props>(src, parent, is_eigen_mutable_map<MapType>::value);
0431 case return_value_policy::reference:
0432 case return_value_policy::automatic:
0433 case return_value_policy::automatic_reference:
0434 return eigen_array_cast<props>(src, none(), is_eigen_mutable_map<MapType>::value);
0435 default:
0436
0437 pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type");
0438 }
0439 }
0440
0441 static constexpr auto name = props::descriptor;
0442
0443
0444
0445
0446 bool load(handle, bool) = delete;
0447 operator MapType() = delete;
0448 template <typename>
0449 using cast_op_type = MapType;
0450 };
0451
0452
0453 template <typename Type>
0454 struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>> : eigen_map_caster<Type> {};
0455
0456
0457
0458 template <typename PlainObjectType, typename StrideType>
0459 struct type_caster<
0460 Eigen::Ref<PlainObjectType, 0, StrideType>,
0461 enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>>
0462 : public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
0463 private:
0464 using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
0465 using props = EigenProps<Type>;
0466 using Scalar = typename props::Scalar;
0467 static_assert(!std::is_pointer<Scalar>::value,
0468 PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
0469 using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
0470 using Array
0471 = array_t<Scalar,
0472 array::forcecast
0473 | ((props::row_major ? props::inner_stride : props::outer_stride) == 1
0474 ? array::c_style
0475 : (props::row_major ? props::outer_stride : props::inner_stride) == 1
0476 ? array::f_style
0477 : 0)>;
0478 static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
0479
0480 std::unique_ptr<MapType> map;
0481 std::unique_ptr<Type> ref;
0482
0483
0484
0485
0486
0487
0488 Array copy_or_ref;
0489
0490 public:
0491 bool load(handle src, bool convert) {
0492
0493
0494 bool need_copy = !isinstance<Array>(src);
0495
0496 EigenConformable<props::row_major> fits;
0497 if (!need_copy) {
0498
0499
0500 auto aref = reinterpret_borrow<Array>(src);
0501
0502 if (aref && (!need_writeable || aref.writeable())) {
0503 fits = props::conformable(aref);
0504 if (!fits) {
0505 return false;
0506 }
0507 if (!fits.template stride_compatible<props>()) {
0508 need_copy = true;
0509 } else {
0510 copy_or_ref = std::move(aref);
0511 }
0512 } else {
0513 need_copy = true;
0514 }
0515 }
0516
0517 if (need_copy) {
0518
0519
0520
0521 if (!convert || need_writeable) {
0522 return false;
0523 }
0524
0525 Array copy = Array::ensure(src);
0526 if (!copy) {
0527 return false;
0528 }
0529 fits = props::conformable(copy);
0530 if (!fits || !fits.template stride_compatible<props>()) {
0531 return false;
0532 }
0533 copy_or_ref = std::move(copy);
0534 loader_life_support::add_patient(copy_or_ref);
0535 }
0536
0537 ref.reset();
0538 map.reset(new MapType(data(copy_or_ref),
0539 fits.rows,
0540 fits.cols,
0541 make_stride(fits.stride.outer(), fits.stride.inner())));
0542 ref.reset(new Type(*map));
0543
0544 return true;
0545 }
0546
0547
0548 operator Type *() { return ref.get(); }
0549
0550 operator Type &() { return *ref; }
0551 template <typename _T>
0552 using cast_op_type = pybind11::detail::cast_op_type<_T>;
0553
0554 private:
0555 template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
0556 Scalar *data(Array &a) {
0557 return a.mutable_data();
0558 }
0559
0560 template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
0561 const Scalar *data(Array &a) {
0562 return a.data();
0563 }
0564
0565
0566
0567 template <typename S>
0568 using stride_ctor_default = bool_constant<S::InnerStrideAtCompileTime != Eigen::Dynamic
0569 && S::OuterStrideAtCompileTime != Eigen::Dynamic
0570 && std::is_default_constructible<S>::value>;
0571
0572
0573 template <typename S>
0574 using stride_ctor_dual
0575 = bool_constant<!stride_ctor_default<S>::value
0576 && std::is_constructible<S, EigenIndex, EigenIndex>::value>;
0577
0578
0579 template <typename S>
0580 using stride_ctor_outer
0581 = bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
0582 && S::OuterStrideAtCompileTime == Eigen::Dynamic
0583 && S::InnerStrideAtCompileTime != Eigen::Dynamic
0584 && std::is_constructible<S, EigenIndex>::value>;
0585 template <typename S>
0586 using stride_ctor_inner
0587 = bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
0588 && S::InnerStrideAtCompileTime == Eigen::Dynamic
0589 && S::OuterStrideAtCompileTime != Eigen::Dynamic
0590 && std::is_constructible<S, EigenIndex>::value>;
0591
0592 template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
0593 static S make_stride(EigenIndex, EigenIndex) {
0594 return S();
0595 }
0596 template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
0597 static S make_stride(EigenIndex outer, EigenIndex inner) {
0598 return S(outer, inner);
0599 }
0600 template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
0601 static S make_stride(EigenIndex outer, EigenIndex) {
0602 return S(outer);
0603 }
0604 template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
0605 static S make_stride(EigenIndex, EigenIndex inner) {
0606 return S(inner);
0607 }
0608 };
0609
0610
0611
0612
0613
0614 template <typename Type>
0615 struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
0616 static_assert(!std::is_pointer<typename Type::Scalar>::value,
0617 PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
0618
0619 protected:
0620 using Matrix
0621 = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
0622 using props = EigenProps<Matrix>;
0623
0624 public:
0625 static handle cast(const Type &src, return_value_policy , handle ) {
0626 handle h = eigen_encapsulate<props>(new Matrix(src));
0627 return h;
0628 }
0629 static handle cast(const Type *src, return_value_policy policy, handle parent) {
0630 return cast(*src, policy, parent);
0631 }
0632
0633 static constexpr auto name = props::descriptor;
0634
0635
0636
0637
0638 bool load(handle, bool) = delete;
0639 operator Type() = delete;
0640 template <typename>
0641 using cast_op_type = Type;
0642 };
0643
0644 template <typename Type>
0645 struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
0646 using Scalar = typename Type::Scalar;
0647 static_assert(!std::is_pointer<Scalar>::value,
0648 PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
0649 using StorageIndex = remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())>;
0650 using Index = typename Type::Index;
0651 static constexpr bool rowMajor = Type::IsRowMajor;
0652
0653 bool load(handle src, bool) {
0654 if (!src) {
0655 return false;
0656 }
0657
0658 auto obj = reinterpret_borrow<object>(src);
0659 object sparse_module = module_::import("scipy.sparse");
0660 object matrix_type = sparse_module.attr(rowMajor ? "csr_matrix" : "csc_matrix");
0661
0662 if (!type::handle_of(obj).is(matrix_type)) {
0663 try {
0664 obj = matrix_type(obj);
0665 } catch (const error_already_set &) {
0666 return false;
0667 }
0668 }
0669
0670 auto values = array_t<Scalar>((object) obj.attr("data"));
0671 auto innerIndices = array_t<StorageIndex>((object) obj.attr("indices"));
0672 auto outerIndices = array_t<StorageIndex>((object) obj.attr("indptr"));
0673 auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
0674 auto nnz = obj.attr("nnz").cast<Index>();
0675
0676 if (!values || !innerIndices || !outerIndices) {
0677 return false;
0678 }
0679
0680 value = EigenMapSparseMatrix<Scalar,
0681 Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),
0682 StorageIndex>(shape[0].cast<Index>(),
0683 shape[1].cast<Index>(),
0684 std::move(nnz),
0685 outerIndices.mutable_data(),
0686 innerIndices.mutable_data(),
0687 values.mutable_data());
0688
0689 return true;
0690 }
0691
0692 static handle cast(const Type &src, return_value_policy , handle ) {
0693 const_cast<Type &>(src).makeCompressed();
0694
0695 object matrix_type
0696 = module_::import("scipy.sparse").attr(rowMajor ? "csr_matrix" : "csc_matrix");
0697
0698 array data(src.nonZeros(), src.valuePtr());
0699 array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
0700 array innerIndices(src.nonZeros(), src.innerIndexPtr());
0701
0702 return matrix_type(pybind11::make_tuple(
0703 std::move(data), std::move(innerIndices), std::move(outerIndices)),
0704 pybind11::make_tuple(src.rows(), src.cols()))
0705 .release();
0706 }
0707
0708 PYBIND11_TYPE_CASTER(Type,
0709 const_name<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[",
0710 "scipy.sparse.csc_matrix[")
0711 + npy_format_descriptor<Scalar>::name + const_name("]"));
0712 };
0713
0714 PYBIND11_NAMESPACE_END(detail)
0715 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)