Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • jcarpent/eigenpy
  • gsaurel/eigenpy
  • stack-of-tasks/eigenpy
3 results
Select Git revision
Show changes
Showing
with 1234 additions and 256 deletions
/*
* Copyright 2020-2022 INRIA
* Copyright 2020-2024 INRIA
*/
#ifndef __eigenpy_numpy_hpp__
#define __eigenpy_numpy_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/config.hpp"
#ifndef PY_ARRAY_UNIQUE_SYMBOL
#define PY_ARRAY_UNIQUE_SYMBOL EIGENPY_ARRAY_API
#endif
// For compatibility with Numpy 2.x. See:
// https://numpy.org/devdocs/reference/c-api/array.html#c.NPY_API_SYMBOL_ATTRIBUTE
#define NPY_API_SYMBOL_ATTRIBUTE EIGENPY_DLLAPI
// When building with MSVC, Python headers use some pragma operator to link
// against the Python DLL.
// Unfortunately, it can link against the wrong build type of the library
// leading to some linking issue.
// Boost::Python provides a helper specifically dedicated to selecting the right
// Python library depending on build type, so let's make use of it.
// Numpy headers drags Python with them. As a result, it
// is necessary to include this helper before including Numpy.
// See: https://github.com/stack-of-tasks/eigenpy/pull/514
#include <boost/python/detail/wrap_python.hpp>
#include <numpy/numpyconfig.h>
#ifdef NPY_1_8_API_VERSION
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#endif
// Allow compiling against NumPy 1.x and 2.x. See:
// https://github.com/numpy/numpy/blob/afea8fd66f6bdbde855f5aff0b4e73eb0213c646/doc/source/reference/c-api/array.rst#L1224
#if NPY_ABI_VERSION < 0x02000000
#define PyArray_DescrProto PyArray_Descr
#endif
#include <numpy/ndarrayobject.h>
#include <numpy/ufuncobject.h>
#if NPY_ABI_VERSION < 0x02000000
static inline PyArray_ArrFuncs* PyDataType_GetArrFuncs(PyArray_Descr* descr) {
return descr->f;
}
#endif
/* PEP 674 disallow using macros as l-values
see : https://peps.python.org/pep-0674/
*/
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE)
static inline void _Py_SET_TYPE(PyObject* o, PyTypeObject* type) {
Py_TYPE(o) = type;
}
#define Py_SET_TYPE(o, type) _Py_SET_TYPE((PyObject*)(o), type)
#endif
#if defined _WIN32 || defined __CYGWIN__
#define EIGENPY_GET_PY_ARRAY_TYPE(array) \
call_PyArray_MinScalarType(array)->type_num
......@@ -26,68 +63,140 @@
#define EIGENPY_GET_PY_ARRAY_TYPE(array) PyArray_MinScalarType(array)->type_num
#endif
#include <complex>
namespace eigenpy {
void EIGENPY_DLLAPI import_numpy();
int EIGENPY_DLLAPI PyArray_TypeNum(PyTypeObject* type);
// By default, the Scalar is considered as a Python object
template <typename Scalar>
template <typename Scalar, typename Enable = void>
struct NumpyEquivalentType {
enum { type_code = NPY_USERDEF };
};
template <>
struct NumpyEquivalentType<float> {
enum { type_code = NPY_FLOAT };
struct NumpyEquivalentType<bool> {
enum { type_code = NPY_BOOL };
};
template <>
struct NumpyEquivalentType<std::complex<float> > {
enum { type_code = NPY_CFLOAT };
struct NumpyEquivalentType<char> {
enum { type_code = NPY_INT8 };
};
template <>
struct NumpyEquivalentType<double> {
enum { type_code = NPY_DOUBLE };
struct NumpyEquivalentType<unsigned char> {
enum { type_code = NPY_UINT8 };
};
template <>
struct NumpyEquivalentType<std::complex<double> > {
enum { type_code = NPY_CDOUBLE };
struct NumpyEquivalentType<int8_t> {
enum { type_code = NPY_INT8 };
};
template <>
struct NumpyEquivalentType<long double> {
enum { type_code = NPY_LONGDOUBLE };
struct NumpyEquivalentType<int16_t> {
enum { type_code = NPY_INT16 };
};
template <>
struct NumpyEquivalentType<std::complex<long double> > {
enum { type_code = NPY_CLONGDOUBLE };
struct NumpyEquivalentType<uint16_t> {
enum { type_code = NPY_UINT16 };
};
template <>
struct NumpyEquivalentType<bool> {
enum { type_code = NPY_BOOL };
struct NumpyEquivalentType<int32_t> {
enum { type_code = NPY_INT32 };
};
template <>
struct NumpyEquivalentType<uint32_t> {
enum { type_code = NPY_UINT32 };
};
// On Windows, long is a 32 bytes type but it's a different type than int
// See https://github.com/stack-of-tasks/eigenpy/pull/455
#if defined _WIN32 || defined __CYGWIN__
template <>
struct NumpyEquivalentType<long> {
enum { type_code = NPY_INT32 };
};
template <>
struct NumpyEquivalentType<unsigned long> {
enum { type_code = NPY_UINT32 };
};
#endif // WIN32
template <>
struct NumpyEquivalentType<int> {
enum { type_code = NPY_INT };
struct NumpyEquivalentType<int64_t> {
enum { type_code = NPY_INT64 };
};
template <>
struct NumpyEquivalentType<unsigned int> {
enum { type_code = NPY_UINT };
struct NumpyEquivalentType<uint64_t> {
enum { type_code = NPY_UINT64 };
};
// On Mac, long is a 64 bytes type but it's a different type than int64_t
// See https://github.com/stack-of-tasks/eigenpy/pull/455
#if defined __APPLE__
template <>
struct NumpyEquivalentType<long> {
enum { type_code = NPY_LONG };
enum { type_code = NPY_INT64 };
};
// #if defined _WIN32 || defined __CYGWIN__
template <>
struct NumpyEquivalentType<long long> {
struct NumpyEquivalentType<unsigned long> {
enum { type_code = NPY_UINT64 };
};
#endif // MAC
// On Linux, long long is a 64 bytes type but it's a different type than int64_t
// See https://github.com/stack-of-tasks/eigenpy/pull/455
#if defined __linux__
#include <type_traits>
template <typename Scalar>
struct NumpyEquivalentType<
Scalar,
typename std::enable_if<!std::is_same<int64_t, long long>::value &&
std::is_same<Scalar, long long>::value>::type> {
enum { type_code = NPY_LONGLONG };
};
// #else
// template <> struct NumpyEquivalentType<long long> { enum { type_code =
// NPY_LONGLONG };};
// #endif
template <typename Scalar>
struct NumpyEquivalentType<
Scalar, typename std::enable_if<
!std::is_same<uint64_t, unsigned long long>::value &&
std::is_same<Scalar, unsigned long long>::value>::type> {
enum { type_code = NPY_ULONGLONG };
};
#endif // Linux
template <>
struct NumpyEquivalentType<unsigned long> {
enum { type_code = NPY_ULONG };
struct NumpyEquivalentType<float> {
enum { type_code = NPY_FLOAT };
};
template <>
struct NumpyEquivalentType<double> {
enum { type_code = NPY_DOUBLE };
};
template <>
struct NumpyEquivalentType<long double> {
enum { type_code = NPY_LONGDOUBLE };
};
template <>
struct NumpyEquivalentType<std::complex<float>> {
enum { type_code = NPY_CFLOAT };
};
template <>
struct NumpyEquivalentType<std::complex<double>> {
enum { type_code = NPY_CDOUBLE };
};
template <>
struct NumpyEquivalentType<std::complex<long double>> {
enum { type_code = NPY_CLONGDOUBLE };
};
template <typename Scalar>
......@@ -122,7 +231,7 @@ EIGENPY_DLLAPI PyArray_Descr* call_PyArray_DescrFromType(int typenum);
EIGENPY_DLLAPI void call_PyArray_InitArrFuncs(PyArray_ArrFuncs* funcs);
EIGENPY_DLLAPI int call_PyArray_RegisterDataType(PyArray_Descr* dtype);
EIGENPY_DLLAPI int call_PyArray_RegisterDataType(PyArray_DescrProto* dtype);
EIGENPY_DLLAPI int call_PyArray_RegisterCanCast(PyArray_Descr* descr,
int totype,
......@@ -170,7 +279,7 @@ inline void call_PyArray_InitArrFuncs(PyArray_ArrFuncs* funcs) {
PyArray_InitArrFuncs(funcs);
}
inline int call_PyArray_RegisterDataType(PyArray_Descr* dtype) {
inline int call_PyArray_RegisterDataType(PyArray_DescrProto* dtype) {
return PyArray_RegisterDataType(dtype);
}
......
......@@ -25,12 +25,12 @@ namespace python {
namespace converter {
template <typename T>
struct expected_pytype_for_arg<boost::optional<T> >
struct expected_pytype_for_arg<boost::optional<T>>
: expected_pytype_for_arg<T> {};
#ifdef EIGENPY_WITH_CXX17_SUPPORT
template <typename T>
struct expected_pytype_for_arg<std::optional<T> > : expected_pytype_for_arg<T> {
struct expected_pytype_for_arg<std::optional<T>> : expected_pytype_for_arg<T> {
};
#endif
......@@ -88,7 +88,7 @@ struct OptionalToPython {
}
static void registration() {
if (!check_registration<OptionalTpl<T> >()) {
if (!check_registration<OptionalTpl<T>>()) {
bp::to_python_converter<OptionalTpl<T>, OptionalToPython, true>();
}
}
......@@ -122,7 +122,7 @@ void OptionalFromPython<T, OptionalTpl>::construct(
PyObject *obj_ptr, bp::converter::rvalue_from_python_stage1_data *memory) {
// create storage
using rvalue_storage_t =
bp::converter::rvalue_from_python_storage<OptionalTpl<T> >;
bp::converter::rvalue_from_python_storage<OptionalTpl<T>>;
void *storage =
reinterpret_cast<rvalue_storage_t *>(reinterpret_cast<void *>(memory))
->storage.bytes;
......@@ -140,8 +140,8 @@ void OptionalFromPython<T, OptionalTpl>::construct(
template <typename T, template <typename> class OptionalTpl>
void OptionalFromPython<T, OptionalTpl>::registration() {
bp::converter::registry::push_back(
&convertible, &construct, bp::type_id<OptionalTpl<T> >(),
bp::converter::expected_pytype_for_arg<OptionalTpl<T> >::get_pytype);
&convertible, &construct, bp::type_id<OptionalTpl<T>>(),
bp::converter::expected_pytype_for_arg<OptionalTpl<T>>::get_pytype);
}
} // namespace detail
......
......@@ -21,7 +21,7 @@ struct rvalue_from_python_data<Eigen::QuaternionBase<Quaternion> const&>
};
template <class Quaternion>
struct implicit<Quaternion, Eigen::QuaternionBase<Quaternion> > {
struct implicit<Quaternion, Eigen::QuaternionBase<Quaternion>> {
typedef Quaternion Source;
typedef Eigen::QuaternionBase<Quaternion> Target;
......@@ -69,7 +69,7 @@ template <typename QuaternionDerived>
class QuaternionVisitor;
template <typename Scalar, int Options>
struct call<Eigen::Quaternion<Scalar, Options> > {
struct call<Eigen::Quaternion<Scalar, Options>> {
typedef Eigen::Quaternion<Scalar, Options> Quaternion;
static inline void expose() { QuaternionVisitor<Quaternion>::expose(); }
......@@ -82,7 +82,7 @@ struct call<Eigen::Quaternion<Scalar, Options> > {
template <typename Quaternion>
class QuaternionVisitor
: public bp::def_visitor<QuaternionVisitor<Quaternion> > {
: public bp::def_visitor<QuaternionVisitor<Quaternion>> {
typedef Eigen::QuaternionBase<Quaternion> QuaternionBase;
typedef typename QuaternionBase::Scalar Scalar;
......@@ -364,7 +364,8 @@ class QuaternionVisitor
"'q*v' (rotating 'v' by 'q'), "
"'q==q', 'q!=q', 'q[0..3]'.",
bp::no_init)
.def(QuaternionVisitor<Quaternion>());
.def(QuaternionVisitor<Quaternion>())
.def(IdVisitor<Quaternion>());
// Cast to Eigen::QuaternionBase and vice-versa
bp::implicitly_convertible<Quaternion, QuaternionBase>();
......
......@@ -20,6 +20,25 @@ namespace eigenpy {
struct EIGENPY_DLLAPI Register {
static PyArray_Descr *getPyArrayDescr(PyTypeObject *py_type_ptr);
static PyArray_Descr *getPyArrayDescrFromTypeNum(const int type_num);
template <typename Scalar>
static PyArray_Descr *getPyArrayDescrFromScalarType() {
if (!isNumpyNativeType<Scalar>()) {
const std::type_info &info = typeid(Scalar);
if (instance().type_to_py_type_bindings.find(&info) !=
instance().type_to_py_type_bindings.end()) {
PyTypeObject *py_type = instance().type_to_py_type_bindings[&info];
return instance().py_array_descr_bindings[py_type];
} else
return nullptr;
} else {
PyArray_Descr *new_descr =
call_PyArray_DescrFromType(NumpyEquivalentType<Scalar>::type_code);
return new_descr;
}
}
template <typename Scalar>
static bool isRegistered() {
return isRegistered(Register::getPyType<Scalar>());
......@@ -87,7 +106,7 @@ struct EIGENPY_DLLAPI Register {
static Register &instance();
private:
Register(){};
Register() {};
struct Compare_PyTypeObject {
bool operator()(const PyTypeObject *a, const PyTypeObject *b) const {
......
......@@ -7,6 +7,7 @@
#define __eigenpy_registration_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/registration_class.hpp"
namespace eigenpy {
......@@ -44,12 +45,33 @@ inline bool register_symbolic_link_to_registered_type() {
const bp::converter::registration* reg =
bp::converter::registry::query(info);
bp::handle<> class_obj(reg->get_class_object());
bp::incref(class_obj.get());
bp::scope().attr(reg->get_class_object()->tp_name) = bp::object(class_obj);
return true;
}
return false;
}
/// Same as \see register_symbolic_link_to_registered_type() but apply \p
/// visitor on \tparam T if it already exists
template <typename T, typename Visitor>
inline bool register_symbolic_link_to_registered_type(const Visitor& visitor) {
if (eigenpy::check_registration<T>()) {
const bp::type_info info = bp::type_id<T>();
const bp::converter::registration* reg =
bp::converter::registry::query(info);
bp::handle<> class_obj(reg->get_class_object());
bp::incref(class_obj.get());
bp::object object(class_obj);
bp::scope().attr(reg->get_class_object()->tp_name) = object;
registration_class<T> cl(object);
cl.def(visitor);
return true;
}
return false;
}
} // namespace eigenpy
#endif // ifndef __eigenpy_registration_hpp__
/*
* Copyright 2023, INRIA
*/
#ifndef __eigenpy_registration_class_hpp__
#define __eigenpy_registration_class_hpp__
#include <boost/python/class.hpp>
#include "eigenpy/fwd.hpp"
namespace eigenpy {
/*! Copy of the \see boost::python::class_
* This class allow to add methods to an existing class without registering it
* again.
**/
template <class W>
class registration_class {
public:
using self = registration_class;
/// \p object Hold the namespace of the class that will be modified
registration_class(bp::object object) : m_object(object) {}
/// \see boost::python::class_::def(bp::def_visitor<Derived> const& visitor)
template <class Visitor>
self& def(Visitor const& visitor) {
visitor.visit(*this);
return *this;
}
template <class DerivedVisitor>
self& def(bp::def_visitor<DerivedVisitor> const& visitor) {
static_cast<DerivedVisitor const&>(visitor).visit(*this);
return *this;
}
/// \see boost::python::class_::def(char const* name, F f)
template <class F>
self& def(char const* name, F f) {
def_impl(bp::detail::unwrap_wrapper((W*)0), name, f,
bp::detail::def_helper<char const*>(0), &f);
return *this;
}
/// \see boost::python::class_::def(char const* name, A1 a1, A2 const& a2)
template <class A1, class A2>
self& def(char const* name, A1 a1, A2 const& a2) {
def_maybe_overloads(name, a1, a2, &a2);
return *this;
}
/// \see boost::python::class_::def(char const* name, Fn fn, A1 const& a1, A2
/// const& a2)
template <class Fn, class A1, class A2>
self& def(char const* name, Fn fn, A1 const& a1, A2 const& a2) {
def_impl(bp::detail::unwrap_wrapper((W*)0), name, fn,
bp::detail::def_helper<A1, A2>(a1, a2), &fn);
return *this;
}
/// \see boost::python::class_::def(char const* name, Fn fn, A1 const& a1, A2
/// const& a2, A3 const& a3)
template <class Fn, class A1, class A2, class A3>
self& def(char const* name, Fn fn, A1 const& a1, A2 const& a2, A3 const& a3) {
def_impl(bp::detail::unwrap_wrapper((W*)0), name, fn,
bp::detail::def_helper<A1, A2, A3>(a1, a2, a3), &fn);
return *this;
}
private:
/// \see boost::python::class_::def_impl(T*, char const* name, Fn fn, Helper
/// const& helper, ...)
template <class T, class Fn, class Helper>
inline void def_impl(T*, char const* name, Fn fn, Helper const& helper, ...) {
bp::objects::add_to_namespace(
m_object, name,
make_function(fn, helper.policies(), helper.keywords(),
bp::detail::get_signature(fn, (T*)0)),
helper.doc());
def_default(name, fn, helper,
boost::mpl::bool_<Helper::has_default_implementation>());
}
/// \see boost::python::class_::def_default(char const* name, Fn, Helper
/// const& helper, boost::mpl::bool_<true>)
template <class Fn, class Helper>
inline void def_default(char const* name, Fn, Helper const& helper,
boost::mpl::bool_<true>) {
bp::detail::error::virtual_function_default<
W, Fn>::must_be_derived_class_member(helper.default_implementation());
bp::objects::add_to_namespace(
m_object, name,
make_function(helper.default_implementation(), helper.policies(),
helper.keywords()));
}
/// \see boost::python::class_::def_default(char const*, Fn, Helper const&,
/// boost::mpl::bool_<false>)
template <class Fn, class Helper>
inline void def_default(char const*, Fn, Helper const&,
boost::mpl::bool_<false>) {}
/// \see boost::python::class_::def_maybe_overloads(char const* name, SigT
/// sig,OverloadsT const& overloads,bp::detail::overloads_base const*)
template <class OverloadsT, class SigT>
void def_maybe_overloads(char const* name, SigT sig,
OverloadsT const& overloads,
bp::detail::overloads_base const*)
{
bp::detail::define_with_defaults(name, overloads, *this,
bp::detail::get_signature(sig));
}
/// \see boost::python::class_::def_maybe_overloads(char const* name, Fn fn,
/// A1 const& a1, ...)
template <class Fn, class A1>
void def_maybe_overloads(char const* name, Fn fn, A1 const& a1, ...) {
def_impl(bp::detail::unwrap_wrapper((W*)0), name, fn,
bp::detail::def_helper<A1>(a1), &fn);
}
private:
bp::object m_object;
};
} // namespace eigenpy
#endif // ifndef __eigenpy_registration_class_hpp__
//
// Copyright (c) 2014-2020 CNRS INRIA
// Copyright (c) 2014-2024 CNRS INRIA
//
#ifndef __eigenpy_scalar_conversion_hpp__
#define __eigenpy_scalar_conversion_hpp__
#include "eigenpy/config.hpp"
#include <boost/numeric/conversion/conversion_traits.hpp>
#include <complex>
namespace eigenpy {
template <typename SCALAR1, typename SCALAR2>
struct FromTypeToType : public boost::false_type {};
template <typename SCALAR>
struct FromTypeToType<SCALAR, SCALAR> : public boost::true_type {};
template <typename Source, typename Target>
struct FromTypeToType
: public boost::mpl::if_c<std::is_same<Source, Target>::value,
std::true_type,
typename boost::numeric::conversion_traits<
Source, Target>::subranged>::type {};
/// FromTypeToType specialization to manage std::complex
template <typename ScalarSource, typename ScalarTarget>
struct FromTypeToType<std::complex<ScalarSource>, std::complex<ScalarTarget>>
: public boost::mpl::if_c<
std::is_same<ScalarSource, ScalarTarget>::value, std::true_type,
typename boost::numeric::conversion_traits<
ScalarSource, ScalarTarget>::subranged>::type {};
template <>
struct FromTypeToType<int, long> : public boost::true_type {};
template <>
struct FromTypeToType<int, float> : public boost::true_type {};
template <>
struct FromTypeToType<int, std::complex<float> > : public boost::true_type {};
template <>
struct FromTypeToType<int, double> : public boost::true_type {};
template <>
struct FromTypeToType<int, std::complex<double> > : public boost::true_type {};
template <>
struct FromTypeToType<int, long double> : public boost::true_type {};
template <>
struct FromTypeToType<int, std::complex<long double> >
: public boost::true_type {};
template <>
struct FromTypeToType<long, float> : public boost::true_type {};
template <>
struct FromTypeToType<long, std::complex<float> > : public boost::true_type {};
template <>
struct FromTypeToType<long, double> : public boost::true_type {};
template <>
struct FromTypeToType<long, std::complex<double> > : public boost::true_type {};
template <>
struct FromTypeToType<long, long double> : public boost::true_type {};
template <>
struct FromTypeToType<long, std::complex<long double> >
: public boost::true_type {};
template <>
struct FromTypeToType<float, std::complex<float> > : public boost::true_type {};
template <>
struct FromTypeToType<float, double> : public boost::true_type {};
template <>
struct FromTypeToType<float, std::complex<double> > : public boost::true_type {
};
template <>
struct FromTypeToType<float, long double> : public boost::true_type {};
template <>
struct FromTypeToType<float, std::complex<long double> >
: public boost::true_type {};
template <>
struct FromTypeToType<double, std::complex<double> > : public boost::true_type {
};
template <>
struct FromTypeToType<double, long double> : public boost::true_type {};
template <>
struct FromTypeToType<double, std::complex<long double> >
: public boost::true_type {};
} // namespace eigenpy
#endif // __eigenpy_scalar_conversion_hpp__
/*
* Copyright 2024 INRIA
*/
#ifndef __eigenpy_scipy_allocator_hpp__
#define __eigenpy_scipy_allocator_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/eigen-allocator.hpp"
#include "eigenpy/scipy-type.hpp"
#include "eigenpy/register.hpp"
namespace eigenpy {
template <typename EigenType, typename BaseType>
struct scipy_allocator_impl;
template <typename EigenType>
struct scipy_allocator_impl_sparse_matrix;
template <typename MatType>
struct scipy_allocator_impl<
MatType,
Eigen::SparseMatrixBase<typename remove_const_reference<MatType>::type>>
: scipy_allocator_impl_sparse_matrix<MatType> {};
template <typename MatType>
struct scipy_allocator_impl<const MatType,
const Eigen::SparseMatrixBase<
typename remove_const_reference<MatType>::type>>
: scipy_allocator_impl_sparse_matrix<const MatType> {};
// template <typename MatType>
// struct scipy_allocator_impl<MatType &, Eigen::MatrixBase<MatType> > :
// scipy_allocator_impl_sparse_matrix<MatType &>
//{};
template <typename MatType>
struct scipy_allocator_impl<const MatType &,
const Eigen::SparseMatrixBase<MatType>>
: scipy_allocator_impl_sparse_matrix<const MatType &> {};
template <typename EigenType,
typename BaseType = typename get_eigen_base_type<EigenType>::type>
struct ScipyAllocator : scipy_allocator_impl<EigenType, BaseType> {};
template <typename MatType>
struct scipy_allocator_impl_sparse_matrix {
template <typename SimilarMatrixType>
static PyObject *allocate(
const Eigen::SparseCompressedBase<SimilarMatrixType> &mat_,
bool copy = false) {
EIGENPY_UNUSED_VARIABLE(copy);
typedef typename SimilarMatrixType::Scalar Scalar;
typedef typename SimilarMatrixType::StorageIndex StorageIndex;
enum { IsRowMajor = SimilarMatrixType::IsRowMajor };
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> DataVector;
typedef const Eigen::Map<const DataVector> MapDataVector;
typedef Eigen::Matrix<StorageIndex, Eigen::Dynamic, 1> StorageIndexVector;
typedef Eigen::Matrix<int32_t, Eigen::Dynamic, 1> ScipyStorageIndexVector;
typedef const Eigen::Map<const StorageIndexVector> MapStorageIndexVector;
SimilarMatrixType &mat = mat_.const_cast_derived();
bp::object scipy_sparse_matrix_type =
ScipyType::get_pytype_object<SimilarMatrixType>();
MapDataVector data(mat.valuePtr(), mat.nonZeros());
MapStorageIndexVector outer_indices(
mat.outerIndexPtr(), (IsRowMajor ? mat.rows() : mat.cols()) + 1);
MapStorageIndexVector inner_indices(mat.innerIndexPtr(), mat.nonZeros());
bp::object scipy_sparse_matrix;
if (mat.rows() == 0 &&
mat.cols() == 0) // handle the specific case of empty matrix
{
// PyArray_Descr* npy_type =
// Register::getPyArrayDescrFromScalarType<Scalar>(); bp::dict args;
// args["dtype"] =
// bp::object(bp::handle<>(bp::borrowed(npy_type->typeobj)));
// args["shape"] = bp::object(bp::handle<>(bp::borrowed(Py_None)));
// scipy_sparse_matrix =
// scipy_sparse_matrix_type(*bp::make_tuple(0,0),**args);
scipy_sparse_matrix = scipy_sparse_matrix_type(
Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>(0, 0));
} else if (mat.nonZeros() == 0) {
scipy_sparse_matrix =
scipy_sparse_matrix_type(bp::make_tuple(mat.rows(), mat.cols()));
} else {
scipy_sparse_matrix = scipy_sparse_matrix_type(bp::make_tuple(
DataVector(data),
ScipyStorageIndexVector(inner_indices.template cast<int32_t>()),
ScipyStorageIndexVector(
outer_indices.template cast<int32_t>()))); //,
// bp::make_tuple(mat.rows(),
// mat.cols())));
}
Py_INCREF(scipy_sparse_matrix.ptr());
return scipy_sparse_matrix.ptr();
}
};
// template <typename MatType>
// struct scipy_allocator_impl_sparse_matrix<MatType &> {
// template <typename SimilarMatrixType>
// static PyArrayObject *allocate(Eigen::PlainObjectBase<SimilarMatrixType>
// &mat,
// npy_intp nd, npy_intp *shape) {
// typedef typename SimilarMatrixType::Scalar Scalar;
// enum {
// NPY_ARRAY_MEMORY_CONTIGUOUS =
// SimilarMatrixType::IsRowMajor ? NPY_ARRAY_CARRAY : NPY_ARRAY_FARRAY
// };
//
// if (NumpyType::sharedMemory()) {
// const int Scalar_type_code = Register::getTypeCode<Scalar>();
// PyArrayObject *pyArray = (PyArrayObject *)call_PyArray_New(
// getPyArrayType(), static_cast<int>(nd), shape, Scalar_type_code,
// mat.data(), NPY_ARRAY_MEMORY_CONTIGUOUS | NPY_ARRAY_ALIGNED);
//
// return pyArray;
// } else {
// return NumpyAllocator<MatType>::allocate(mat, nd, shape);
// }
// }
// };
#if EIGEN_VERSION_AT_LEAST(3, 2, 0)
// template <typename MatType, int Options, typename Stride>
// struct scipy_allocator_impl_sparse_matrix<Eigen::Ref<MatType, Options,
// Stride> > {
// typedef Eigen::Ref<MatType, Options, Stride> RefType;
//
// static PyArrayObject *allocate(RefType &mat, npy_intp nd, npy_intp *shape)
// {
// typedef typename RefType::Scalar Scalar;
// enum {
// NPY_ARRAY_MEMORY_CONTIGUOUS =
// RefType::IsRowMajor ? NPY_ARRAY_CARRAY : NPY_ARRAY_FARRAY
// };
//
// if (NumpyType::sharedMemory()) {
// const int Scalar_type_code = Register::getTypeCode<Scalar>();
// const bool reverse_strides = MatType::IsRowMajor || (mat.rows() == 1);
// Eigen::DenseIndex inner_stride = reverse_strides ? mat.outerStride()
// : mat.innerStride(),
// outer_stride = reverse_strides ? mat.innerStride()
// : mat.outerStride();
//
// const int elsize =
// call_PyArray_DescrFromType(Scalar_type_code)->elsize; npy_intp
// strides[2] = {elsize * inner_stride, elsize * outer_stride};
//
// PyArrayObject *pyArray = (PyArrayObject *)call_PyArray_New(
// getPyArrayType(), static_cast<int>(nd), shape, Scalar_type_code,
// strides, mat.data(), NPY_ARRAY_MEMORY_CONTIGUOUS |
// NPY_ARRAY_ALIGNED);
//
// return pyArray;
// } else {
// return NumpyAllocator<MatType>::allocate(mat, nd, shape);
// }
// }
// };
#endif
// template <typename MatType>
// struct scipy_allocator_impl_sparse_matrix<const MatType &> {
// template <typename SimilarMatrixType>
// static PyArrayObject *allocate(
// const Eigen::PlainObjectBase<SimilarMatrixType> &mat, npy_intp nd,
// npy_intp *shape) {
// typedef typename SimilarMatrixType::Scalar Scalar;
// enum {
// NPY_ARRAY_MEMORY_CONTIGUOUS_RO = SimilarMatrixType::IsRowMajor
// ? NPY_ARRAY_CARRAY_RO
// : NPY_ARRAY_FARRAY_RO
// };
//
// if (NumpyType::sharedMemory()) {
// const int Scalar_type_code = Register::getTypeCode<Scalar>();
// PyArrayObject *pyArray = (PyArrayObject *)call_PyArray_New(
// getPyArrayType(), static_cast<int>(nd), shape, Scalar_type_code,
// const_cast<Scalar *>(mat.data()),
// NPY_ARRAY_MEMORY_CONTIGUOUS_RO | NPY_ARRAY_ALIGNED);
//
// return pyArray;
// } else {
// return NumpyAllocator<MatType>::allocate(mat, nd, shape);
// }
// }
// };
#if EIGEN_VERSION_AT_LEAST(3, 2, 0)
// template <typename MatType, int Options, typename Stride>
// struct scipy_allocator_impl_sparse_matrix<
// const Eigen::Ref<const MatType, Options, Stride> > {
// typedef const Eigen::Ref<const MatType, Options, Stride> RefType;
//
// static PyArrayObject *allocate(RefType &mat, npy_intp nd, npy_intp *shape)
// {
// typedef typename RefType::Scalar Scalar;
// enum {
// NPY_ARRAY_MEMORY_CONTIGUOUS_RO =
// RefType::IsRowMajor ? NPY_ARRAY_CARRAY_RO : NPY_ARRAY_FARRAY_RO
// };
//
// if (NumpyType::sharedMemory()) {
// const int Scalar_type_code = Register::getTypeCode<Scalar>();
//
// const bool reverse_strides = MatType::IsRowMajor || (mat.rows() == 1);
// Eigen::DenseIndex inner_stride = reverse_strides ? mat.outerStride()
// : mat.innerStride(),
// outer_stride = reverse_strides ? mat.innerStride()
// : mat.outerStride();
//
// const int elsize =
// call_PyArray_DescrFromType(Scalar_type_code)->elsize; npy_intp
// strides[2] = {elsize * inner_stride, elsize * outer_stride};
//
// PyArrayObject *pyArray = (PyArrayObject *)call_PyArray_New(
// getPyArrayType(), static_cast<int>(nd), shape, Scalar_type_code,
// strides, const_cast<Scalar *>(mat.data()),
// NPY_ARRAY_MEMORY_CONTIGUOUS_RO | NPY_ARRAY_ALIGNED);
//
// return pyArray;
// } else {
// return NumpyAllocator<MatType>::allocate(mat, nd, shape);
// }
// }
// };
#endif
} // namespace eigenpy
#endif // ifndef __eigenpy_scipy_allocator_hpp__
/*
* Copyright 2024 INRIA
*/
#ifndef __eigenpy_scipy_type_hpp__
#define __eigenpy_scipy_type_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/register.hpp"
#include "eigenpy/scalar-conversion.hpp"
#include "eigenpy/numpy-type.hpp"
namespace eigenpy {
struct EIGENPY_DLLAPI ScipyType {
static ScipyType& getInstance();
static void sharedMemory(const bool value);
static bool sharedMemory();
static bp::object getScipyType();
static const PyTypeObject* getScipyCSRMatrixType();
static const PyTypeObject* getScipyCSCMatrixType();
template <typename SparseMatrix>
static bp::object get_pytype_object(
const Eigen::SparseMatrixBase<SparseMatrix>* ptr = nullptr) {
EIGENPY_UNUSED_VARIABLE(ptr);
return SparseMatrix::IsRowMajor ? getInstance().csr_matrix_obj
: getInstance().csc_matrix_obj;
}
template <typename SparseMatrix>
static PyTypeObject const* get_pytype(
const Eigen::SparseMatrixBase<SparseMatrix>* ptr = nullptr) {
EIGENPY_UNUSED_VARIABLE(ptr);
return SparseMatrix::IsRowMajor ? getInstance().csr_matrix_type
: getInstance().csc_matrix_type;
}
static int get_numpy_type_num(const bp::object& obj) {
const PyTypeObject* type = Py_TYPE(obj.ptr());
EIGENPY_USED_VARIABLE_ONLY_IN_DEBUG_MODE(type);
assert(type == getInstance().csr_matrix_type ||
type == getInstance().csc_matrix_type);
bp::object dtype = obj.attr("dtype");
const PyArray_Descr* npy_type =
reinterpret_cast<PyArray_Descr*>(dtype.ptr());
return npy_type->type_num;
}
protected:
ScipyType();
bp::object sparse_module;
// SciPy types
bp::object csr_matrix_obj, csc_matrix_obj;
PyTypeObject *csr_matrix_type, *csc_matrix_type;
bool shared_memory;
};
} // namespace eigenpy
#endif // ifndef __eigenpy_scipy_type_hpp__
/*
* Copyright 2017, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017 CNRS
* Copyright 2024 Inria
*/
#ifndef __eigenpy_bfgs_preconditioners_hpp__
......@@ -26,7 +15,7 @@ namespace eigenpy {
template <typename Preconditioner>
struct BFGSPreconditionerBaseVisitor
: public bp::def_visitor<BFGSPreconditionerBaseVisitor<Preconditioner> > {
: public bp::def_visitor<BFGSPreconditionerBaseVisitor<Preconditioner>> {
typedef Eigen::VectorXd VectorType;
template <class PyClass>
void visit(PyClass& cl) const {
......@@ -49,6 +38,7 @@ struct BFGSPreconditionerBaseVisitor
static void expose(const std::string& name) {
bp::class_<Preconditioner>(name, bp::no_init)
.def(IdVisitor<Preconditioner>())
.def(BFGSPreconditionerBaseVisitor<Preconditioner>());
}
};
......@@ -56,7 +46,7 @@ struct BFGSPreconditionerBaseVisitor
template <typename Preconditioner>
struct LimitedBFGSPreconditionerBaseVisitor
: public bp::def_visitor<
LimitedBFGSPreconditionerBaseVisitor<Preconditioner> > {
LimitedBFGSPreconditionerBaseVisitor<Preconditioner>> {
template <class PyClass>
void visit(PyClass& cl) const {
cl.def(PreconditionerBaseVisitor<Preconditioner>())
......@@ -68,6 +58,7 @@ struct LimitedBFGSPreconditionerBaseVisitor
static void expose(const std::string& name) {
bp::class_<Preconditioner>(name.c_str(), bp::no_init)
.def(IdVisitor<Preconditioner>())
.def(LimitedBFGSPreconditionerBaseVisitor<Preconditioner>());
}
};
......
/*
* Copyright 2017, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017 CNRS
* Copyright 2024 Inria
*/
#ifndef __eigenpy_basic_preconditioners_hpp__
......@@ -25,7 +14,7 @@ namespace eigenpy {
template <typename Preconditioner>
struct PreconditionerBaseVisitor
: public bp::def_visitor<PreconditionerBaseVisitor<Preconditioner> > {
: public bp::def_visitor<PreconditionerBaseVisitor<Preconditioner>> {
typedef Eigen::MatrixXd MatrixType;
typedef Eigen::VectorXd VectorType;
......@@ -62,7 +51,7 @@ struct PreconditionerBaseVisitor
template <typename Scalar>
struct DiagonalPreconditionerVisitor
: PreconditionerBaseVisitor<Eigen::DiagonalPreconditioner<Scalar> > {
: PreconditionerBaseVisitor<Eigen::DiagonalPreconditioner<Scalar>> {
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> MatrixType;
typedef Eigen::DiagonalPreconditioner<Scalar> Preconditioner;
......@@ -81,7 +70,8 @@ struct DiagonalPreconditionerVisitor
"A preconditioner based on the digonal entrie.\n"
"This class allows to approximately solve for A.x = b problems "
"assuming A is a diagonal matrix.",
bp::no_init);
bp::no_init)
.def(IdVisitor<Preconditioner>());
}
};
......@@ -89,7 +79,7 @@ struct DiagonalPreconditionerVisitor
template <typename Scalar>
struct LeastSquareDiagonalPreconditionerVisitor
: PreconditionerBaseVisitor<
Eigen::LeastSquareDiagonalPreconditioner<Scalar> > {
Eigen::LeastSquareDiagonalPreconditioner<Scalar>> {
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> MatrixType;
typedef Eigen::LeastSquareDiagonalPreconditioner<Scalar> Preconditioner;
......@@ -103,7 +93,8 @@ struct LeastSquareDiagonalPreconditionerVisitor
"his class allows to approximately solve for A' A x = A' b problems "
"assuming A' A is a diagonal matrix.",
bp::no_init)
.def(DiagonalPreconditionerVisitor<Scalar>());
.def(DiagonalPreconditionerVisitor<Scalar>())
.def(IdVisitor<Preconditioner>());
}
};
#endif
......@@ -117,7 +108,8 @@ struct IdentityPreconditionerVisitor
static void expose() {
bp::class_<Preconditioner>("IdentityPreconditioner", bp::no_init)
.def(PreconditionerBaseVisitor<Preconditioner>());
.def(PreconditionerBaseVisitor<Preconditioner>())
.def(IdVisitor<Preconditioner>());
}
};
......
/*
* Copyright 2017, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017 CNRS
*/
#ifndef __eigenpy_conjugate_gradient_hpp__
......@@ -27,7 +15,7 @@ namespace eigenpy {
template <typename ConjugateGradient>
struct ConjugateGradientVisitor
: public boost::python::def_visitor<
ConjugateGradientVisitor<ConjugateGradient> > {
ConjugateGradientVisitor<ConjugateGradient>> {
typedef typename ConjugateGradient::MatrixType MatrixType;
template <class PyClass>
......@@ -43,7 +31,8 @@ struct ConjugateGradientVisitor
static void expose(const std::string& name = "ConjugateGradient") {
bp::class_<ConjugateGradient, boost::noncopyable>(name.c_str(), bp::no_init)
.def(ConjugateGradientVisitor<ConjugateGradient>());
.def(ConjugateGradientVisitor<ConjugateGradient>())
.def(IdVisitor<ConjugateGradient>());
}
};
......
/*
* Copyright 2017, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017 CNRS
*/
#ifndef __eigenpy_iterative_solver_base_hpp__
......@@ -24,7 +12,7 @@ namespace eigenpy {
template <typename IterativeSolver>
struct IterativeSolverVisitor : public boost::python::def_visitor<
IterativeSolverVisitor<IterativeSolver> > {
IterativeSolverVisitor<IterativeSolver>> {
typedef typename IterativeSolver::MatrixType MatrixType;
typedef typename IterativeSolver::Preconditioner Preconditioner;
typedef Eigen::VectorXd VectorType;
......
/*
* Copyright 2017-2018, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017-2018 CNRS
*/
#ifndef __eigenpy_least_square_conjugate_gradient_hpp__
......@@ -26,8 +14,8 @@ namespace eigenpy {
template <typename LeastSquaresConjugateGradient>
struct LeastSquaresConjugateGradientVisitor
: public boost::python::def_visitor<LeastSquaresConjugateGradientVisitor<
LeastSquaresConjugateGradient> > {
: public boost::python::def_visitor<
LeastSquaresConjugateGradientVisitor<LeastSquaresConjugateGradient>> {
typedef Eigen::MatrixXd MatrixType;
template <class PyClass>
......@@ -46,7 +34,8 @@ struct LeastSquaresConjugateGradientVisitor
"LeastSquaresConjugateGradient", bp::no_init)
.def(IterativeSolverVisitor<LeastSquaresConjugateGradient>())
.def(LeastSquaresConjugateGradientVisitor<
LeastSquaresConjugateGradient>());
LeastSquaresConjugateGradient>())
.def(IdVisitor<LeastSquaresConjugateGradient>());
}
};
......
/*
* Copyright 2017, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017 CNRS
*/
#ifndef __eigenpy_sparse_solver_base_hpp__
......@@ -23,7 +11,7 @@ namespace eigenpy {
template <typename SparseSolver>
struct SparseSolverVisitor
: public bp::def_visitor<SparseSolverVisitor<SparseSolver> > {
: public bp::def_visitor<SparseSolverVisitor<SparseSolver>> {
typedef Eigen::VectorXd VectorType;
template <class PyClass>
......
/*
* Copyright 2017, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017 CNRS
*/
#ifndef __eigenpy_preconditioners_hpp__
......
//
// Copyright (c) 2024-2025 INRIA
//
#ifndef __eigenpy_sparse_eigen_from_python_hpp__
#define __eigenpy_sparse_eigen_from_python_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/eigen-allocator.hpp"
#include "eigenpy/scipy-type.hpp"
#include "eigenpy/scalar-conversion.hpp"
namespace eigenpy {
template <typename SparseMatrixType>
struct expected_pytype_for_arg<SparseMatrixType,
Eigen::SparseMatrixBase<SparseMatrixType>> {
static PyTypeObject const *get_pytype() {
PyTypeObject const *py_type = ScipyType::get_pytype<SparseMatrixType>();
return py_type;
}
};
} // namespace eigenpy
namespace boost {
namespace python {
namespace converter {
template <typename Scalar, int Options, typename StorageIndex>
struct expected_pytype_for_arg<
Eigen::SparseMatrix<Scalar, Options, StorageIndex>>
: eigenpy::expected_pytype_for_arg<
Eigen::SparseMatrix<Scalar, Options, StorageIndex>> {};
template <typename Scalar, int Options, typename StorageIndex>
struct rvalue_from_python_data<
Eigen::SparseMatrix<Scalar, Options, StorageIndex> const &>
: ::eigenpy::rvalue_from_python_data<
Eigen::SparseMatrix<Scalar, Options, StorageIndex> const &> {
typedef Eigen::SparseMatrix<Scalar, Options, StorageIndex> T;
EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(T const &)
};
template <typename Derived>
struct rvalue_from_python_data<Eigen::SparseMatrixBase<Derived> const &>
: ::eigenpy::rvalue_from_python_data<Derived const &> {
EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(Derived const &)
};
} // namespace converter
} // namespace python
} // namespace boost
namespace boost {
namespace python {
namespace detail {
// template <typename TensorType>
// struct referent_storage<Eigen::TensorRef<TensorType> &> {
// typedef Eigen::TensorRef<TensorType> RefType;
// typedef ::eigenpy::details::referent_storage_eigen_ref<RefType>
// StorageType; typedef typename ::eigenpy::aligned_storage<
// referent_size<StorageType &>::value>::type type;
// };
// template <typename TensorType>
// struct referent_storage<const Eigen::TensorRef<const TensorType> &> {
// typedef Eigen::TensorRef<const TensorType> RefType;
// typedef ::eigenpy::details::referent_storage_eigen_ref<RefType>
// StorageType; typedef typename ::eigenpy::aligned_storage<
// referent_size<StorageType &>::value>::type type;
// };
} // namespace detail
} // namespace python
} // namespace boost
namespace eigenpy {
template <typename SparseMatrixType>
struct eigen_from_py_impl<SparseMatrixType,
Eigen::SparseMatrixBase<SparseMatrixType>> {
typedef typename SparseMatrixType::Scalar Scalar;
/// \brief Determine if pyObj can be converted into a MatType object
static void *convertible(PyObject *pyObj);
/// \brief Allocate memory and copy pyObj in the new storage
static void construct(PyObject *pyObj,
bp::converter::rvalue_from_python_stage1_data *memory);
static void registration();
};
template <typename SparseMatrixType>
void *eigen_from_py_impl<
SparseMatrixType,
Eigen::SparseMatrixBase<SparseMatrixType>>::convertible(PyObject *pyObj) {
const PyTypeObject *type = Py_TYPE(pyObj);
const PyTypeObject *sparse_matrix_py_type =
ScipyType::get_pytype<SparseMatrixType>();
typedef typename SparseMatrixType::Scalar Scalar;
if (type != sparse_matrix_py_type) return 0;
bp::object obj(bp::handle<>(bp::borrowed(pyObj)));
const int type_num = ScipyType::get_numpy_type_num(obj);
if (!np_type_is_convertible_into_scalar<Scalar>(type_num)) return 0;
return pyObj;
}
template <typename MatOrRefType>
void eigen_sparse_matrix_from_py_construct(
PyObject *pyObj, bp::converter::rvalue_from_python_stage1_data *memory) {
typedef typename MatOrRefType::Scalar Scalar;
typedef typename MatOrRefType::StorageIndex StorageIndex;
typedef Eigen::Map<MatOrRefType> MapMatOrRefType;
bp::converter::rvalue_from_python_storage<MatOrRefType> *storage =
reinterpret_cast<
bp::converter::rvalue_from_python_storage<MatOrRefType> *>(
reinterpret_cast<void *>(memory));
void *raw_ptr = storage->storage.bytes;
bp::object obj(bp::handle<>(bp::borrowed(pyObj)));
const int type_num_python_sparse_matrix = ScipyType::get_numpy_type_num(obj);
const int type_num_eigen_sparse_matrix = Register::getTypeCode<Scalar>();
if (type_num_eigen_sparse_matrix == type_num_python_sparse_matrix) {
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> DataVector;
// typedef const Eigen::Ref<const DataVector> RefDataVector;
DataVector data = bp::extract<DataVector>(obj.attr("data"));
bp::tuple shape = bp::extract<bp::tuple>(obj.attr("shape"));
typedef Eigen::Matrix<StorageIndex, Eigen::Dynamic, 1> StorageIndexVector;
// typedef const Eigen::Ref<const StorageIndexVector>
// RefStorageIndexVector;
StorageIndexVector indices =
bp::extract<StorageIndexVector>(obj.attr("indices"));
StorageIndexVector indptr =
bp::extract<StorageIndexVector>(obj.attr("indptr"));
const Eigen::Index m = bp::extract<Eigen::Index>(shape[0]),
n = bp::extract<Eigen::Index>(shape[1]),
nnz = bp::extract<Eigen::Index>(obj.attr("nnz"));
// Handle the specific case of the null matrix
Scalar *data_ptr = nullptr;
StorageIndex *indices_ptr = nullptr;
if (nnz > 0) {
data_ptr = data.data();
indices_ptr = indices.data();
}
MapMatOrRefType sparse_map(m, n, nnz, indptr.data(), indices_ptr, data_ptr);
#if EIGEN_VERSION_AT_LEAST(3, 4, 90)
sparse_map.sortInnerIndices();
#endif
new (raw_ptr) MatOrRefType(sparse_map);
}
memory->convertible = storage->storage.bytes;
}
template <typename SparseMatrixType>
void eigen_from_py_impl<SparseMatrixType,
Eigen::SparseMatrixBase<SparseMatrixType>>::
construct(PyObject *pyObj,
bp::converter::rvalue_from_python_stage1_data *memory) {
eigen_sparse_matrix_from_py_construct<SparseMatrixType>(pyObj, memory);
}
template <typename SparseMatrixType>
void eigen_from_py_impl<
SparseMatrixType,
Eigen::SparseMatrixBase<SparseMatrixType>>::registration() {
bp::converter::registry::push_back(
reinterpret_cast<void *(*)(_object *)>(&eigen_from_py_impl::convertible),
&eigen_from_py_impl::construct, bp::type_id<SparseMatrixType>()
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
,
&eigenpy::expected_pytype_for_arg<SparseMatrixType>::get_pytype
#endif
);
}
template <typename SparseMatrixType>
struct eigen_from_py_converter_impl<SparseMatrixType,
Eigen::SparseMatrixBase<SparseMatrixType>> {
static void registration() {
EigenFromPy<SparseMatrixType>::registration();
// Add conversion to Eigen::SparseMatrixBase<SparseMatrixType>
typedef Eigen::SparseMatrixBase<SparseMatrixType> SparseMatrixBase;
EigenFromPy<SparseMatrixBase>::registration();
// // Add conversion to Eigen::Ref<SparseMatrixType>
// typedef Eigen::Ref<SparseMatrixType> RefType;
// EigenFromPy<SparseMatrixType>::registration();
//
// // Add conversion to Eigen::Ref<const SparseMatrixType>
// typedef const Eigen::Ref<const SparseMatrixType> ConstRefType;
// EigenFromPy<ConstRefType>::registration();
}
};
template <typename SparseMatrixType>
struct EigenFromPy<Eigen::SparseMatrixBase<SparseMatrixType>>
: EigenFromPy<SparseMatrixType> {
typedef EigenFromPy<SparseMatrixType> EigenFromPyDerived;
typedef Eigen::SparseMatrixBase<SparseMatrixType> Base;
static void registration() {
bp::converter::registry::push_back(
reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
&EigenFromPy::construct, bp::type_id<Base>()
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
,
&eigenpy::expected_pytype_for_arg<SparseMatrixType>::get_pytype
#endif
);
}
};
//
// template <typename TensorType>
// struct EigenFromPy<Eigen::TensorRef<TensorType> > {
// typedef Eigen::TensorRef<TensorType> RefType;
// typedef typename TensorType::Scalar Scalar;
//
// /// \brief Determine if pyObj can be converted into a MatType object
// static void *convertible(PyObject *pyObj) {
// if (!call_PyArray_Check(pyObj)) return 0;
// PyArrayObject *pyArray = reinterpret_cast<PyArrayObject *>(pyObj);
// if (!PyArray_ISWRITEABLE(pyArray)) return 0;
// return EigenFromPy<TensorType>::convertible(pyObj);
// }
//
// static void registration() {
// bp::converter::registry::push_back(
// reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
// &eigen_from_py_construct<RefType>, bp::type_id<RefType>()
// #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
// ,
// &eigenpy::expected_pytype_for_arg<TensorType>::get_pytype
// #endif
// );
// }
//};
// template <typename TensorType>
// struct EigenFromPy<const Eigen::TensorRef<const TensorType> > {
// typedef const Eigen::TensorRef<const TensorType> ConstRefType;
// typedef typename TensorType::Scalar Scalar;
//
// /// \brief Determine if pyObj can be converted into a MatType object
// static void *convertible(PyObject *pyObj) {
// return EigenFromPy<TensorType>::convertible(pyObj);
// }
//
// static void registration() {
// bp::converter::registry::push_back(
// reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
// &eigen_from_py_construct<ConstRefType>, bp::type_id<ConstRefType>()
// #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
// ,
// &eigenpy::expected_pytype_for_arg<TensorType>::get_pytype
// #endif
// );
// }
// };
} // namespace eigenpy
#endif // __eigenpy_sparse_eigen_from_python_hpp__
///
/// Copyright (c) 2023-2024 CNRS INRIA
///
#ifndef __eigenpy_utils_std_array_hpp__
#define __eigenpy_utils_std_array_hpp__
#include <boost/python/suite/indexing/indexing_suite.hpp>
#include "eigenpy/std-vector.hpp"
#include <array>
namespace eigenpy {
template <typename Container, bool NoProxy, class SliceAllocator,
class DerivedPolicies>
class array_indexing_suite;
namespace details {
template <typename Container, bool NoProxy, class SliceAllocator>
class final_array_derived_policies
: public array_indexing_suite<
Container, NoProxy, SliceAllocator,
final_array_derived_policies<Container, NoProxy, SliceAllocator>> {};
} // namespace details
template <typename Container, bool NoProxy = false,
class SliceAllocator = std::allocator<typename Container::value_type>,
class DerivedPolicies = details::final_array_derived_policies<
Container, NoProxy, SliceAllocator>>
class array_indexing_suite
: public bp::vector_indexing_suite<Container, NoProxy, DerivedPolicies> {
public:
typedef typename Container::value_type data_type;
typedef typename Container::value_type key_type;
typedef typename Container::size_type index_type;
typedef typename Container::size_type size_type;
typedef typename Container::difference_type difference_type;
typedef std::vector<data_type, SliceAllocator> slice_vector_type;
static constexpr std::size_t Size = std::tuple_size<Container>{};
template <class Class>
static void extension_def(Class &) {}
// throws exception
static void delete_item(Container &, index_type) {
PyErr_SetString(PyExc_NotImplementedError,
"Cannot delete item from std::array type.");
bp::throw_error_already_set();
}
// throws exception
static void delete_slice(Container &, index_type, index_type) {
PyErr_SetString(PyExc_NotImplementedError,
"Cannot delete slice from std::array type.");
bp::throw_error_already_set();
}
static void set_slice(Container &container, index_type from, index_type to,
data_type const &v) {
if (from >= to) {
PyErr_SetString(PyExc_NotImplementedError,
"Setting this slice would insert into an std::array, "
"which is not supported.");
bp::throw_error_already_set();
} else {
std::fill(container.begin() + from, container.begin() + to, v);
}
}
template <class Iter>
static void set_slice(Container &container, index_type from, index_type to,
Iter first, Iter last) {
if (from >= to) {
PyErr_SetString(PyExc_NotImplementedError,
"Setting this slice would insert into an std::array, "
"which is not supported.");
bp::throw_error_already_set();
} else {
if (long(to - from) == std::distance(first, last)) {
std::copy(first, last, container.begin() + from);
} else {
PyErr_SetString(PyExc_NotImplementedError,
"Size of std::array slice and size of right-hand side "
"iterator are incompatible.");
bp::throw_error_already_set();
}
}
}
static bp::object get_slice(Container &container, index_type from,
index_type to) {
if (from > to) return bp::object(slice_vector_type());
slice_vector_type out;
for (size_t i = from; i < to; i++) {
out.push_back(container[i]);
}
return bp::object(std::move(out));
}
};
/// \brief Expose an std::array (a C++11 fixed-size array) from a given type
/// \tparam array_type std::array type to expose
/// \tparam NoProxy When set to false, the elements will be copied when
/// returned to Python.
/// \tparam SliceAllocator Allocator type to use for slices of std::array type
/// accessed using e.g. __getitem__[0:4] in Python. These slices are returned as
/// std::vector (dynamic size).
template <typename array_type, bool NoProxy = false,
class SliceAllocator =
std::allocator<typename array_type::value_type>>
struct StdArrayPythonVisitor {
typedef typename array_type::value_type value_type;
static ::boost::python::list tolist(array_type &self, const bool deep_copy) {
return details::build_list<array_type, NoProxy>::run(self, deep_copy);
}
static void expose(const std::string &class_name,
const std::string &doc_string = "") {
expose(class_name, doc_string, EmptyPythonVisitor());
}
template <typename DerivedVisitor>
static void expose(const std::string &class_name,
const bp::def_visitor<DerivedVisitor> &visitor) {
expose(class_name, "", visitor);
}
template <typename DerivedVisitor>
static void expose(const std::string &class_name,
const std::string &doc_string,
const bp::def_visitor<DerivedVisitor> &visitor) {
if (!register_symbolic_link_to_registered_type<array_type>()) {
bp::class_<array_type> cl(class_name.c_str(), doc_string.c_str());
cl.def(bp::init<const array_type &>(bp::args("self", "other"),
"Copy constructor"));
cl.def(IdVisitor<array_type>());
array_indexing_suite<array_type, NoProxy, SliceAllocator> indexing_suite;
cl.def(indexing_suite)
.def(visitor)
.def("tolist", tolist,
(bp::arg("self"), bp::arg("deep_copy") = false),
"Returns the std::array as a Python list.");
}
}
};
/// Exposes std::array<MatrixType, Size>
template <typename MatrixType, std::size_t Size>
void exposeStdArrayEigenSpecificType(const char *name) {
std::ostringstream oss;
oss << "StdArr";
oss << Size << "_" << name;
typedef std::array<MatrixType, Size> array_type;
StdArrayPythonVisitor<array_type, false,
Eigen::aligned_allocator<MatrixType>>::
expose(oss.str(),
details::overload_base_get_item_for_std_vector<array_type>());
}
} // namespace eigenpy
#endif // ifndef __eigenpy_utils_std_array_hpp__
/// Copyright (c) 2016-2022 CNRS INRIA
/// This file was taken from Pinocchio (header
/// <pinocchio/bindings/python/utils/std-vector.hpp>)
/// Copyright (c) 2024, INRIA
///
#ifndef __eigenpy_utils_map_hpp__
#define __eigenpy_utils_map_hpp__
#ifndef __eigenpy_std_map_hpp__
#define __eigenpy_std_map_hpp__
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
#include "eigenpy/map.hpp"
#include "eigenpy/deprecated.hpp"
#include <map>
namespace eigenpy {
namespace details {
template <typename Container>
struct overload_base_get_item_for_std_map
: public boost::python::def_visitor<
overload_base_get_item_for_std_map<Container> > {
typedef typename Container::value_type value_type;
typedef typename Container::value_type::second_type data_type;
typedef typename Container::key_type key_type;
typedef typename Container::key_type index_type;
template <class Class>
void visit(Class& cl) const {
cl.def("__getitem__", &base_get_item);
}
private:
static boost::python::object base_get_item(
boost::python::back_reference<Container&> container, PyObject* i_) {
index_type idx = convert_index(container.get(), i_);
typename Container::iterator i = container.get().find(idx);
if (i == container.get().end()) {
PyErr_SetString(PyExc_KeyError, "Invalid key");
bp::throw_error_already_set();
}
typename bp::to_python_indirect<data_type&,
bp::detail::make_reference_holder>
convert;
return bp::object(bp::handle<>(convert(i->second)));
}
static index_type convert_index(Container& /*container*/, PyObject* i_) {
bp::extract<key_type const&> i(i_);
if (i.check()) {
return i();
} else {
bp::extract<key_type> i(i_);
if (i.check()) return i();
}
PyErr_SetString(PyExc_TypeError, "Invalid index type");
bp::throw_error_already_set();
return index_type();
}
};
using overload_base_get_item_for_std_map EIGENPY_DEPRECATED_MESSAGE(
"Use overload_base_get_item_for_map<> instead.") =
overload_base_get_item_for_map<Container>;
namespace details {
using ::eigenpy::overload_base_get_item_for_std_map;
} // namespace details
/**
* @brief Expose an std::map from a type given as template argument.
*
* @param[in] T Type to expose as std::map<T>.
* @param[in] Compare Type for the Compare in std::map<T,Compare,Allocator>.
* @param[in] Allocator Type for the Allocator in
* std::map<T,Compare,Allocator>.
* @param[in] NoProxy When set to false, the elements will be copied when
* returned to Python.
*/
template <class Key, class T, class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T>>,
bool NoProxy = false>
struct StdMapPythonVisitor
: GenericMapVisitor<std::map<Key, T, Compare, Allocator>, NoProxy> {};
namespace python {
// fix previous mistake
using ::eigenpy::StdMapPythonVisitor;
} // namespace python
} // namespace eigenpy
#endif // ifndef __eigenpy_utils_map_hpp__
#endif // ifndef __eigenpy_std_map_hpp__
//
// Copyright (c) 2023 INRIA
//
#ifndef __eigenpy_utils_std_pair_hpp__
#define __eigenpy_utils_std_pair_hpp__
#include <boost/python.hpp>
#include <utility>
namespace eigenpy {
template <typename pair_type>
struct StdPairConverter {
typedef typename pair_type::first_type T1;
typedef typename pair_type::second_type T2;
static PyObject* convert(const pair_type& pair) {
return boost::python::incref(
boost::python::make_tuple(pair.first, pair.second).ptr());
}
static void* convertible(PyObject* obj) {
if (!PyTuple_CheckExact(obj)) return 0;
if (PyTuple_Size(obj) != 2) return 0;
{
boost::python::tuple tuple(boost::python::borrowed(obj));
boost::python::extract<T1> elt1(tuple[0]);
if (!elt1.check()) return 0;
boost::python::extract<T2> elt2(tuple[1]);
if (!elt2.check()) return 0;
}
return obj;
}
static void construct(
PyObject* obj,
boost::python::converter::rvalue_from_python_stage1_data* memory) {
boost::python::tuple tuple(boost::python::borrowed(obj));
void* storage =
reinterpret_cast<
boost::python::converter::rvalue_from_python_storage<pair_type>*>(
reinterpret_cast<void*>(memory))
->storage.bytes;
new (storage) pair_type(boost::python::extract<T1>(tuple[0]),
boost::python::extract<T2>(tuple[1]));
memory->convertible = storage;
}
static PyTypeObject const* get_pytype() {
PyTypeObject const* py_type = &PyTuple_Type;
return py_type;
}
static void registration() {
boost::python::converter::registry::push_back(
&convertible, &construct, boost::python::type_id<pair_type>()
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
,
get_pytype
#endif
);
boost::python::to_python_converter<pair_type, StdPairConverter, true>();
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_utils_std_pair_hpp__