summaryrefslogtreecommitdiff
path: root/ext/pybind11/include/pybind11/eigen.h
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pybind11/include/pybind11/eigen.h')
-rw-r--r--ext/pybind11/include/pybind11/eigen.h239
1 files changed, 239 insertions, 0 deletions
diff --git a/ext/pybind11/include/pybind11/eigen.h b/ext/pybind11/include/pybind11/eigen.h
new file mode 100644
index 000000000..0a1208e16
--- /dev/null
+++ b/ext/pybind11/include/pybind11/eigen.h
@@ -0,0 +1,239 @@
+/*
+ pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices
+
+ Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "numpy.h"
+
+#if defined(__INTEL_COMPILER)
+# pragma warning(disable: 1682) // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem)
+#elif defined(__GNUG__) || defined(__clang__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+#include <Eigen/Core>
+#include <Eigen/SparseCore>
+
+#if defined(__GNUG__) || defined(__clang__)
+# pragma GCC diagnostic pop
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
+#endif
+
+NAMESPACE_BEGIN(pybind11)
+NAMESPACE_BEGIN(detail)
+
+template <typename T> using is_eigen_dense = is_template_base_of<Eigen::DenseBase, T>;
+template <typename T> using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
+template <typename T> using is_eigen_ref = is_template_base_of<Eigen::RefBase, T>;
+
+// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above. This
+// basically covers anything that can be assigned to a dense matrix but that don't have a typical
+// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and
+// SelfAdjointView fall into this category.
+template <typename T> using is_eigen_base = bool_constant<
+ is_template_base_of<Eigen::EigenBase, T>::value
+ && !is_eigen_dense<T>::value && !is_eigen_sparse<T>::value
+>;
+
+template<typename Type>
+struct type_caster<Type, enable_if_t<is_eigen_dense<Type>::value && !is_eigen_ref<Type>::value>> {
+ typedef typename Type::Scalar Scalar;
+ static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit;
+ static constexpr bool isVector = Type::IsVectorAtCompileTime;
+
+ bool load(handle src, bool) {
+ auto buf = array_t<Scalar>::ensure(src);
+ if (!buf)
+ return false;
+
+ if (buf.ndim() == 1) {
+ typedef Eigen::InnerStride<> Strides;
+ if (!isVector &&
+ !(Type::RowsAtCompileTime == Eigen::Dynamic &&
+ Type::ColsAtCompileTime == Eigen::Dynamic))
+ return false;
+
+ if (Type::SizeAtCompileTime != Eigen::Dynamic &&
+ buf.shape(0) != (size_t) Type::SizeAtCompileTime)
+ return false;
+
+ Strides::Index n_elts = (Strides::Index) buf.shape(0);
+ Strides::Index unity = 1;
+
+ value = Eigen::Map<Type, 0, Strides>(
+ buf.mutable_data(),
+ rowMajor ? unity : n_elts,
+ rowMajor ? n_elts : unity,
+ Strides(buf.strides(0) / sizeof(Scalar))
+ );
+ } else if (buf.ndim() == 2) {
+ typedef Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> Strides;
+
+ if ((Type::RowsAtCompileTime != Eigen::Dynamic && buf.shape(0) != (size_t) Type::RowsAtCompileTime) ||
+ (Type::ColsAtCompileTime != Eigen::Dynamic && buf.shape(1) != (size_t) Type::ColsAtCompileTime))
+ return false;
+
+ value = Eigen::Map<Type, 0, Strides>(
+ buf.mutable_data(),
+ typename Strides::Index(buf.shape(0)),
+ typename Strides::Index(buf.shape(1)),
+ Strides(buf.strides(rowMajor ? 0 : 1) / sizeof(Scalar),
+ buf.strides(rowMajor ? 1 : 0) / sizeof(Scalar))
+ );
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
+ if (isVector) {
+ return array(
+ { (size_t) src.size() }, // shape
+ { sizeof(Scalar) * static_cast<size_t>(src.innerStride()) }, // strides
+ src.data() // data
+ ).release();
+ } else {
+ return array(
+ { (size_t) src.rows(), // shape
+ (size_t) src.cols() },
+ { sizeof(Scalar) * static_cast<size_t>(src.rowStride()), // strides
+ sizeof(Scalar) * static_cast<size_t>(src.colStride()) },
+ src.data() // data
+ ).release();
+ }
+ }
+
+ PYBIND11_TYPE_CASTER(Type, _("numpy.ndarray[") + npy_format_descriptor<Scalar>::name() +
+ _("[") + rows() + _(", ") + cols() + _("]]"));
+
+protected:
+ template <typename T = Type, enable_if_t<T::RowsAtCompileTime == Eigen::Dynamic, int> = 0>
+ static PYBIND11_DESCR rows() { return _("m"); }
+ template <typename T = Type, enable_if_t<T::RowsAtCompileTime != Eigen::Dynamic, int> = 0>
+ static PYBIND11_DESCR rows() { return _<T::RowsAtCompileTime>(); }
+ template <typename T = Type, enable_if_t<T::ColsAtCompileTime == Eigen::Dynamic, int> = 0>
+ static PYBIND11_DESCR cols() { return _("n"); }
+ template <typename T = Type, enable_if_t<T::ColsAtCompileTime != Eigen::Dynamic, int> = 0>
+ static PYBIND11_DESCR cols() { return _<T::ColsAtCompileTime>(); }
+};
+
+// Eigen::Ref<Derived> satisfies is_eigen_dense, but isn't constructable, so it needs a special
+// type_caster to handle argument copying/forwarding.
+template <typename CVDerived, int Options, typename StrideType>
+struct type_caster<Eigen::Ref<CVDerived, Options, StrideType>> {
+protected:
+ using Type = Eigen::Ref<CVDerived, Options, StrideType>;
+ using Derived = typename std::remove_const<CVDerived>::type;
+ using DerivedCaster = type_caster<Derived>;
+ DerivedCaster derived_caster;
+ std::unique_ptr<Type> value;
+public:
+ bool load(handle src, bool convert) { if (derived_caster.load(src, convert)) { value.reset(new Type(derived_caster.operator Derived&())); return true; } return false; }
+ static handle cast(const Type &src, return_value_policy policy, handle parent) { return DerivedCaster::cast(src, policy, parent); }
+ static handle cast(const Type *src, return_value_policy policy, handle parent) { return DerivedCaster::cast(*src, policy, parent); }
+
+ static PYBIND11_DESCR name() { return DerivedCaster::name(); }
+
+ operator Type*() { return value.get(); }
+ operator Type&() { if (!value) pybind11_fail("Eigen::Ref<...> value not loaded"); return *value; }
+ template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>;
+};
+
+// type_caster for special matrix types (e.g. DiagonalMatrix): load() is not supported, but we can
+// cast them into the python domain by first copying to a regular Eigen::Matrix, then casting that.
+template <typename Type>
+struct type_caster<Type, enable_if_t<is_eigen_base<Type>::value && !is_eigen_ref<Type>::value>> {
+protected:
+ using Matrix = Eigen::Matrix<typename Type::Scalar, Eigen::Dynamic, Eigen::Dynamic>;
+ using MatrixCaster = type_caster<Matrix>;
+public:
+ [[noreturn]] bool load(handle, bool) { pybind11_fail("Unable to load() into specialized EigenBase object"); }
+ static handle cast(const Type &src, return_value_policy policy, handle parent) { return MatrixCaster::cast(Matrix(src), policy, parent); }
+ static handle cast(const Type *src, return_value_policy policy, handle parent) { return MatrixCaster::cast(Matrix(*src), policy, parent); }
+
+ static PYBIND11_DESCR name() { return MatrixCaster::name(); }
+
+ [[noreturn]] operator Type*() { pybind11_fail("Loading not supported for specialized EigenBase object"); }
+ [[noreturn]] operator Type&() { pybind11_fail("Loading not supported for specialized EigenBase object"); }
+ template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>;
+};
+
+template<typename Type>
+struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
+ typedef typename Type::Scalar Scalar;
+ typedef typename std::remove_reference<decltype(*std::declval<Type>().outerIndexPtr())>::type StorageIndex;
+ typedef typename Type::Index Index;
+ static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit;
+
+ bool load(handle src, bool) {
+ if (!src)
+ return false;
+
+ auto obj = reinterpret_borrow<object>(src);
+ object sparse_module = module::import("scipy.sparse");
+ object matrix_type = sparse_module.attr(
+ rowMajor ? "csr_matrix" : "csc_matrix");
+
+ if (obj.get_type() != matrix_type.ptr()) {
+ try {
+ obj = matrix_type(obj);
+ } catch (const error_already_set &) {
+ return false;
+ }
+ }
+
+ auto values = array_t<Scalar>((object) obj.attr("data"));
+ auto innerIndices = array_t<StorageIndex>((object) obj.attr("indices"));
+ auto outerIndices = array_t<StorageIndex>((object) obj.attr("indptr"));
+ auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
+ auto nnz = obj.attr("nnz").cast<Index>();
+
+ if (!values || !innerIndices || !outerIndices)
+ return false;
+
+ value = Eigen::MappedSparseMatrix<Scalar, Type::Flags, StorageIndex>(
+ shape[0].cast<Index>(), shape[1].cast<Index>(), nnz,
+ outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data());
+
+ return true;
+ }
+
+ static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
+ const_cast<Type&>(src).makeCompressed();
+
+ object matrix_type = module::import("scipy.sparse").attr(
+ rowMajor ? "csr_matrix" : "csc_matrix");
+
+ array data((size_t) src.nonZeros(), src.valuePtr());
+ array outerIndices((size_t) (rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
+ array innerIndices((size_t) src.nonZeros(), src.innerIndexPtr());
+
+ return matrix_type(
+ std::make_tuple(data, innerIndices, outerIndices),
+ std::make_pair(src.rows(), src.cols())
+ ).release();
+ }
+
+ PYBIND11_TYPE_CASTER(Type, _<(Type::Flags & Eigen::RowMajorBit) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[")
+ + npy_format_descriptor<Scalar>::name() + _("]"));
+};
+
+NAMESPACE_END(detail)
+NAMESPACE_END(pybind11)
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif