/* pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices Copyright (c) 2016 Wenzel Jakob 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(__GNUG__) || defined(__clang__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wconversion" # pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #include #include #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 class is_eigen_dense { private: template static std::true_type test(const Eigen::DenseBase &); static std::false_type test(...); public: static constexpr bool value = decltype(test(std::declval()))::value; }; template class is_eigen_sparse { private: template static std::true_type test(const Eigen::SparseMatrixBase &); static std::false_type test(...); public: static constexpr bool value = decltype(test(std::declval()))::value; }; template struct type_caster::value>::type> { typedef typename Type::Scalar Scalar; static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit; static constexpr bool isVector = Type::IsVectorAtCompileTime; bool load(handle src, bool) { array_t buffer(src, true); if (!buffer.check()) return false; buffer_info info = buffer.request(); if (info.ndim == 1) { typedef Eigen::Stride Strides; if (!isVector && !(Type::RowsAtCompileTime == Eigen::Dynamic && Type::ColsAtCompileTime == Eigen::Dynamic)) return false; if (Type::SizeAtCompileTime != Eigen::Dynamic && info.shape[0] != (size_t) Type::SizeAtCompileTime) return false; auto strides = Strides(info.strides[0] / sizeof(Scalar), 0); value = Eigen::Map( (Scalar *) info.ptr, typename Strides::Index(info.shape[0]), 1, strides); } else if (info.ndim == 2) { typedef Eigen::Stride Strides; if ((Type::RowsAtCompileTime != Eigen::Dynamic && info.shape[0] != (size_t) Type::RowsAtCompileTime) || (Type::ColsAtCompileTime != Eigen::Dynamic && info.shape[1] != (size_t) Type::ColsAtCompileTime)) return false; auto strides = Strides( info.strides[rowMajor ? 0 : 1] / sizeof(Scalar), info.strides[rowMajor ? 1 : 0] / sizeof(Scalar)); value = Eigen::Map( (Scalar *) info.ptr, typename Strides::Index(info.shape[0]), typename Strides::Index(info.shape[1]), strides); } else { return false; } return true; } static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); } static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) { if (isVector) { return array(buffer_info( /* Pointer to buffer */ const_cast(src.data()), /* Size of one scalar */ sizeof(Scalar), /* Python struct-style format descriptor */ format_descriptor::value, /* Number of dimensions */ 1, /* Buffer dimensions */ { (size_t) src.size() }, /* Strides (in bytes) for each index */ { sizeof(Scalar) } )).release(); } else { return array(buffer_info( /* Pointer to buffer */ const_cast(src.data()), /* Size of one scalar */ sizeof(Scalar), /* Python struct-style format descriptor */ format_descriptor::value, /* Number of dimensions */ isVector ? 1 : 2, /* Buffer dimensions */ { (size_t) src.rows(), (size_t) src.cols() }, /* Strides (in bytes) for each index */ { sizeof(Scalar) * (rowMajor ? (size_t) src.cols() : 1), sizeof(Scalar) * (rowMajor ? 1 : (size_t) src.rows()) } )).release(); } } template using cast_op_type = pybind11::detail::cast_op_type<_T>; static PYBIND11_DESCR name() { return _("numpy.ndarray[dtype=") + npy_format_descriptor::name() + _(", shape=(") + rows() + _(", ") + cols() + _(")]"); } operator Type*() { return &value; } operator Type&() { return value; } protected: template ::type = 0> static PYBIND11_DESCR rows() { return _("m"); } template ::type = 0> static PYBIND11_DESCR rows() { return _(); } template ::type = 0> static PYBIND11_DESCR cols() { return _("n"); } template ::type = 0> static PYBIND11_DESCR cols() { return _(); } protected: Type value; }; template struct type_caster::value>::type> { typedef typename Type::Scalar Scalar; typedef typename std::remove_reference().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; object obj(src, true); 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 &) { PyErr_Clear(); return false; } } auto valuesArray = array_t((object) obj.attr("data")); auto innerIndicesArray = array_t((object) obj.attr("indices")); auto outerIndicesArray = array_t((object) obj.attr("indptr")); auto shape = pybind11::tuple((pybind11::object) obj.attr("shape")); auto nnz = obj.attr("nnz").cast(); if (!valuesArray.check() || !innerIndicesArray.check() || !outerIndicesArray.check()) return false; buffer_info outerIndices = outerIndicesArray.request(); buffer_info innerIndices = innerIndicesArray.request(); buffer_info values = valuesArray.request(); value = Eigen::MappedSparseMatrix( shape[0].cast(), shape[1].cast(), nnz, static_cast(outerIndices.ptr), static_cast(innerIndices.ptr), static_cast(values.ptr) ); return true; } static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); } static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) { const_cast(src).makeCompressed(); object matrix_type = module::import("scipy.sparse").attr( rowMajor ? "csr_matrix" : "csc_matrix"); array data(buffer_info( // Pointer to buffer const_cast(src.valuePtr()), // Size of one scalar sizeof(Scalar), // Python struct-style format descriptor format_descriptor::value, // Number of dimensions 1, // Buffer dimensions { (size_t) src.nonZeros() }, // Strides { sizeof(Scalar) } )); array outerIndices(buffer_info( // Pointer to buffer const_cast(src.outerIndexPtr()), // Size of one scalar sizeof(StorageIndex), // Python struct-style format descriptor format_descriptor::value, // Number of dimensions 1, // Buffer dimensions { (size_t) (rowMajor ? src.rows() : src.cols()) + 1 }, // Strides { sizeof(StorageIndex) } )); array innerIndices(buffer_info( // Pointer to buffer const_cast(src.innerIndexPtr()), // Size of one scalar sizeof(StorageIndex), // Python struct-style format descriptor format_descriptor::value, // Number of dimensions 1, // Buffer dimensions { (size_t) src.nonZeros() }, // Strides { sizeof(StorageIndex) } )); return matrix_type( std::make_tuple(data, innerIndices, outerIndices), std::make_pair(src.rows(), src.cols()) ).release(); } template using cast_op_type = pybind11::detail::cast_op_type<_T>; template ::type = 0> static PYBIND11_DESCR name() { return _("scipy.sparse.csr_matrix[dtype=") + npy_format_descriptor::name() + _("]"); } template ::type = 0> static PYBIND11_DESCR name() { return _("scipy.sparse.csc_matrix[dtype=") + npy_format_descriptor::name() + _("]"); } operator Type*() { return &value; } operator Type&() { return value; } protected: Type value; }; NAMESPACE_END(detail) NAMESPACE_END(pybind11) #if defined(_MSC_VER) #pragma warning(pop) #endif