14 #if defined(__INTEL_COMPILER)
15 # pragma warning(disable: 1682) // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem)
16 #elif defined(__GNUG__) || defined(__clang__)
17 # pragma GCC diagnostic push
18 # pragma GCC diagnostic ignored "-Wconversion"
19 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
23 # pragma GCC diagnostic ignored "-Wdeprecated"
26 # pragma GCC diagnostic ignored "-Wint-in-bool-context"
31 # pragma warning(push)
32 # pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
33 # pragma warning(disable: 4996) // warning C4996: std::unary_negate is deprecated in C++17
37 #include <Eigen/SparseCore>
42 static_assert(EIGEN_VERSION_AT_LEAST(3,2,7),
"Eigen support in pybind11 requires Eigen >= 3.2.7");
44 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
47 using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
48 template <typename MatrixType> using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
49 template <typename MatrixType> using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
51 PYBIND11_NAMESPACE_BEGIN(detail)
53 #if EIGEN_VERSION_AT_LEAST(3,3,0)
54 using EigenIndex = Eigen::Index;
56 using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
60 template <
typename T>
using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>, std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
61 template <
typename T>
using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
62 template <
typename T>
using is_eigen_dense_plain = all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
63 template <
typename T>
using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
68 template <
typename T>
using is_eigen_other = all_of<
69 is_template_base_of<Eigen::EigenBase, T>,
75 bool conformable =
false;
76 EigenIndex rows = 0, cols = 0;
77 EigenDStride stride{0, 0};
78 bool negativestrides =
false;
83 EigenIndex rstride, EigenIndex cstride) :
84 conformable{
true}, rows{r}, cols{c} {
86 if (rstride < 0 || cstride < 0) {
87 negativestrides =
true;
89 stride = {EigenRowMajor ? rstride : cstride ,
90 EigenRowMajor ? cstride : rstride };
95 :
EigenConformable(r, c, r == 1 ? c*stride : stride, c == 1 ? r : r*stride) {}
97 template <
typename props>
bool stride_compatible()
const {
102 (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner() ||
103 (EigenRowMajor ? cols : rows) == 1) &&
104 (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer() ||
105 (EigenRowMajor ? rows : cols) == 1);
107 operator bool()
const {
return conformable; }
111 template <
typename PlainObjectType,
int MapOptions,
typename Str
ideType>
113 template <
typename PlainObjectType,
int Options,
typename Str
ideType>
119 using Scalar =
typename Type::Scalar;
120 using StrideType =
typename eigen_extract_stride<Type>::type;
121 static constexpr EigenIndex
122 rows = Type::RowsAtCompileTime,
123 cols = Type::ColsAtCompileTime,
124 size = Type::SizeAtCompileTime;
125 static constexpr
bool
126 row_major = Type::IsRowMajor,
127 vector = Type::IsVectorAtCompileTime,
128 fixed_rows = rows != Eigen::Dynamic,
129 fixed_cols = cols != Eigen::Dynamic,
130 fixed = size != Eigen::Dynamic,
131 dynamic = !fixed_rows && !fixed_cols;
133 template <EigenIndex i, EigenIndex ifzero>
using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
134 static constexpr EigenIndex inner_stride = if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
135 outer_stride = if_zero<StrideType::OuterStrideAtCompileTime,
136 vector ? size : row_major ? cols : rows>::value;
137 static constexpr
bool dynamic_stride = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
138 static constexpr
bool requires_row_major = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
139 static constexpr
bool requires_col_major = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
145 const auto dims = a.ndim();
146 if (dims < 1 || dims > 2)
152 np_rows = a.shape(0),
153 np_cols = a.shape(1),
154 np_rstride = a.strides(0) /
static_cast<ssize_t
>(
sizeof(Scalar)),
155 np_cstride = a.strides(1) /
static_cast<ssize_t
>(
sizeof(Scalar));
156 if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols))
159 return {np_rows, np_cols, np_rstride, np_cstride};
164 const EigenIndex n = a.shape(0),
165 stride = a.strides(0) /
static_cast<ssize_t
>(
sizeof(Scalar));
168 if (fixed && size != n)
170 return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
176 else if (fixed_cols) {
179 if (cols != n)
return false;
180 return {1, n, stride};
184 if (fixed_rows && rows != n)
return false;
185 return {n, 1, stride};
189 static constexpr
bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
190 static constexpr
bool show_order = is_eigen_dense_map<Type>::value;
191 static constexpr
bool show_c_contiguous = show_order && requires_row_major;
192 static constexpr
bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major;
194 static constexpr
auto descriptor =
196 _(
"[") + _<fixed_rows>(_<(size_t) rows>(), _(
"m")) +
197 _(
", ") + _<fixed_cols>(_<(size_t) cols>(), _(
"n")) +
205 _<show_writeable>(
", flags.writeable",
"") +
206 _<show_c_contiguous>(
", flags.c_contiguous",
"") +
207 _<show_f_contiguous>(
", flags.f_contiguous",
"") +
213 template <
typename props>
handle eigen_array_cast(
typename props::Type
const &src,
handle base =
handle(),
bool writeable =
true) {
214 constexpr ssize_t elem_size =
sizeof(
typename props::Scalar);
217 a =
array({ src.size() }, { elem_size * src.innerStride() }, src.data(),
base);
219 a =
array({ src.rows(), src.cols() }, { elem_size * src.rowStride(), elem_size * src.colStride() },
223 array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
232 template <
typename props,
typename Type>
236 return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
243 template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
244 handle eigen_encapsulate(Type *src) {
245 capsule base(src, [](
void *o) {
delete static_cast<Type *
>(o); });
246 return eigen_ref_array<props>(*src,
base);
251 template<
typename Type>
252 struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
253 using Scalar =
typename Type::Scalar;
256 bool load(
handle src,
bool convert) {
262 auto buf = array::ensure(src);
267 auto dims = buf.ndim();
268 if (dims < 1 || dims > 2)
271 auto fits = props::conformable(buf);
276 value = Type(fits.rows, fits.cols);
277 auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
278 if (dims == 1) ref = ref.squeeze();
279 else if (ref.ndim() == 1) buf = buf.squeeze();
281 int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
294 template <
typename CType>
295 static handle cast_impl(CType *src, return_value_policy policy,
handle parent) {
297 case return_value_policy::take_ownership:
298 case return_value_policy::automatic:
299 return eigen_encapsulate<props>(src);
300 case return_value_policy::move:
301 return eigen_encapsulate<props>(
new CType(std::move(*src)));
302 case return_value_policy::copy:
303 return eigen_array_cast<
props>(*src);
304 case return_value_policy::reference:
305 case return_value_policy::automatic_reference:
306 return eigen_ref_array<props>(*src);
307 case return_value_policy::reference_internal:
308 return eigen_ref_array<props>(*src, parent);
310 throw cast_error(
"unhandled return_value_policy: should not happen!");
317 static handle cast(Type &&src, return_value_policy ,
handle parent) {
318 return cast_impl(&src, return_value_policy::move, parent);
321 static handle cast(
const Type &&src, return_value_policy ,
handle parent) {
322 return cast_impl(&src, return_value_policy::move, parent);
325 static handle cast(Type &src, return_value_policy policy,
handle parent) {
326 if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
327 policy = return_value_policy::copy;
328 return cast_impl(&src, policy, parent);
331 static handle cast(
const Type &src, return_value_policy policy,
handle parent) {
332 if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
333 policy = return_value_policy::copy;
334 return cast(&src, policy, parent);
337 static handle cast(Type *src, return_value_policy policy,
handle parent) {
338 return cast_impl(src, policy, parent);
341 static handle cast(
const Type *src, return_value_policy policy,
handle parent) {
342 return cast_impl(src, policy, parent);
345 static constexpr
auto name = props::descriptor;
347 operator Type*() {
return &value; }
348 operator Type&() {
return value; }
349 operator Type&&() && {
return std::move(value); }
350 template <
typename T>
using cast_op_type = movable_cast_op_type<T>;
369 static handle cast(
const MapType &src, return_value_policy policy,
handle parent) {
371 case return_value_policy::copy:
372 return eigen_array_cast<
props>(src);
373 case return_value_policy::reference_internal:
374 return eigen_array_cast<
props>(src, parent, is_eigen_mutable_map<MapType>::value);
375 case return_value_policy::reference:
376 case return_value_policy::automatic:
377 case return_value_policy::automatic_reference:
378 return eigen_array_cast<
props>(src,
none(), is_eigen_mutable_map<MapType>::value);
381 pybind11_fail(
"Invalid return_value_policy for Eigen Map/Ref/Block type");
385 static constexpr
auto name = props::descriptor;
390 bool load(
handle,
bool) =
delete;
391 operator MapType() =
delete;
392 template <
typename>
using cast_op_type = MapType;
396 template <
typename Type>
struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>>
401 template <
typename PlainObjectType,
typename Str
ideType>
403 Eigen::Ref<PlainObjectType, 0, StrideType>,
404 enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>
407 using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
409 using Scalar =
typename props::Scalar;
410 using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
412 ((props::row_major ? props::inner_stride : props::outer_stride) == 1 ? array::c_style :
413 (props::row_major ? props::outer_stride : props::inner_stride) == 1 ? array::f_style : 0)>;
414 static constexpr
bool need_writeable = is_eigen_mutable_map<Type>::value;
416 std::unique_ptr<MapType> map;
417 std::unique_ptr<Type> ref;
426 bool load(
handle src,
bool convert) {
429 bool need_copy = !isinstance<Array>(src);
435 Array aref = reinterpret_borrow<Array>(src);
437 if (aref && (!need_writeable || aref.writeable())) {
438 fits = props::conformable(aref);
439 if (!fits)
return false;
440 if (!fits.template stride_compatible<props>())
443 copy_or_ref = std::move(aref);
454 if (!convert || need_writeable)
return false;
456 Array copy = Array::ensure(src);
457 if (!copy)
return false;
458 fits = props::conformable(copy);
459 if (!fits || !fits.template stride_compatible<props>())
461 copy_or_ref = std::move(copy);
466 map.reset(
new MapType(data(copy_or_ref), fits.rows, fits.cols, make_stride(fits.stride.outer(), fits.stride.inner())));
467 ref.reset(
new Type(*map));
472 operator Type*() {
return ref.get(); }
473 operator Type&() {
return *ref; }
474 template <
typename _T>
using cast_op_type = pybind11::detail::cast_op_type<_T>;
477 template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value,
int> = 0>
478 Scalar *data(
Array &a) {
return a.mutable_data(); }
480 template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value,
int> = 0>
481 const Scalar *data(
Array &a) {
return a.data(); }
485 template <
typename S>
using stride_ctor_default = bool_constant<
486 S::InnerStrideAtCompileTime != Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
487 std::is_default_constructible<S>::value>;
490 template <
typename S>
using stride_ctor_dual = bool_constant<
491 !stride_ctor_default<S>::value && std::is_constructible<S, EigenIndex, EigenIndex>::value>;
494 template <
typename S>
using stride_ctor_outer = bool_constant<
496 S::OuterStrideAtCompileTime == Eigen::Dynamic && S::InnerStrideAtCompileTime != Eigen::Dynamic &&
497 std::is_constructible<S, EigenIndex>::value>;
498 template <
typename S>
using stride_ctor_inner = bool_constant<
500 S::InnerStrideAtCompileTime == Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
501 std::is_constructible<S, EigenIndex>::value>;
503 template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value,
int> = 0>
504 static S make_stride(EigenIndex, EigenIndex) {
return S(); }
505 template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value,
int> = 0>
506 static S make_stride(EigenIndex outer, EigenIndex inner) {
return S(outer, inner); }
507 template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value,
int> = 0>
508 static S make_stride(EigenIndex outer, EigenIndex) {
return S(outer); }
509 template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value,
int> = 0>
510 static S make_stride(EigenIndex, EigenIndex inner) {
return S(inner); }
518 template <
typename Type>
519 struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
521 using Matrix = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
524 static handle cast(
const Type &src, return_value_policy ,
handle ) {
525 handle h = eigen_encapsulate<props>(
new Matrix(src));
528 static handle cast(
const Type *src, return_value_policy policy,
handle parent) {
return cast(*src, policy, parent); }
530 static constexpr
auto name = props::descriptor;
535 bool load(
handle,
bool) =
delete;
536 operator Type() =
delete;
537 template <
typename>
using cast_op_type = Type;
540 template<
typename Type>
541 struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
542 typedef typename Type::Scalar Scalar;
543 typedef remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())> StorageIndex;
544 typedef typename Type::Index Index;
545 static constexpr
bool rowMajor = Type::IsRowMajor;
547 bool load(
handle src,
bool) {
551 auto obj = reinterpret_borrow<object>(src);
553 object matrix_type = sparse_module.attr(
554 rowMajor ?
"csr_matrix" :
"csc_matrix");
558 obj = matrix_type(obj);
567 auto shape = pybind11::tuple((pybind11::object) obj.attr(
"shape"));
568 auto nnz = obj.attr(
"nnz").cast<Index>();
570 if (!values || !innerIndices || !outerIndices)
573 value = Eigen::MappedSparseMatrix<Scalar, Type::Flags, StorageIndex>(
574 shape[0].cast<Index>(), shape[1].cast<Index>(), nnz,
575 outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data());
580 static handle cast(
const Type &src, return_value_policy ,
handle ) {
581 const_cast<Type&
>(src).makeCompressed();
584 rowMajor ?
"csr_matrix" :
"csc_matrix");
586 array data(src.nonZeros(), src.valuePtr());
587 array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
588 array innerIndices(src.nonZeros(), src.innerIndexPtr());
591 std::make_tuple(data, innerIndices, outerIndices),
592 std::make_pair(src.rows(), src.cols())
596 PYBIND11_TYPE_CASTER(Type, _<(Type::IsRowMajor) != 0>(
"scipy.sparse.csr_matrix[",
"scipy.sparse.csc_matrix[")
600 PYBIND11_NAMESPACE_END(detail)
601 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
603 #if defined(__GNUG__) || defined(__clang__)
604 # pragma GCC diagnostic pop
605 #elif defined(_MSC_VER)
606 # pragma warning(pop)
bool isinstance(handle obj)
static module_ import(const char *name)
Import and return a module or throws error_already_set.
static PYBIND11_NOINLINE void add_patient(handle h)
Annotation for function names.
Annotation indicating that a class derives from another given type.
static handle handle_of()