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

Target

Select target project
  • jcarpent/eigenpy
  • gsaurel/eigenpy
  • stack-of-tasks/eigenpy
3 results
Show changes
Showing
with 1337 additions and 278 deletions
......@@ -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__
......@@ -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>());
}
};
......@@ -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__
......@@ -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>());
}
};
......@@ -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__
......@@ -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__
......
/*
* 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__
......@@ -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__
......
/*
* 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 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);
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__
//
// Copyright (c) 2024 INRIA
//
#ifndef __eigenpy_utils_std_unique_ptr_hpp__
#define __eigenpy_utils_std_unique_ptr_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/utils/traits.hpp"
#include "eigenpy/utils/python-compat.hpp"
#include <boost/python.hpp>
#include <memory>
#include <type_traits>
namespace eigenpy {
namespace details {
/// Transfer std::unique_ptr ownership to an owning holder
template <typename T>
typename std::enable_if<!is_python_primitive_type<T>::value, PyObject*>::type
unique_ptr_to_python(std::unique_ptr<T>&& x) {
typedef bp::objects::pointer_holder<std::unique_ptr<T>, T> holder_t;
if (!x) {
return bp::detail::none();
} else {
return bp::objects::make_ptr_instance<T, holder_t>::execute(x);
}
}
/// Convert and copy the primitive value to python
template <typename T>
typename std::enable_if<is_python_primitive_type<T>::value, PyObject*>::type
unique_ptr_to_python(std::unique_ptr<T>&& x) {
if (!x) {
return bp::detail::none();
} else {
return bp::to_python_value<const T&>()(*x);
}
}
/// std::unique_ptr keep the ownership but a reference to the std::unique_ptr
/// value is created
template <typename T>
typename std::enable_if<!is_python_primitive_type<T>::value, PyObject*>::type
internal_unique_ptr_to_python(std::unique_ptr<T>& x) {
if (!x) {
return bp::detail::none();
} else {
return bp::detail::make_reference_holder::execute(x.get());
}
}
/// Convert and copy the primitive value to python
template <typename T>
typename std::enable_if<is_python_primitive_type<T>::value, PyObject*>::type
internal_unique_ptr_to_python(std::unique_ptr<T>& x) {
if (!x) {
return bp::detail::none();
} else {
return bp::to_python_value<const T&>()(*x);
}
}
/// result_converter of StdUniquePtrCallPolicies
struct StdUniquePtrResultConverter {
template <typename T>
struct apply {
struct type {
typedef typename T::element_type element_type;
PyObject* operator()(T&& x) const {
return unique_ptr_to_python(std::forward<T>(x));
}
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
PyTypeObject const* get_pytype() const {
return bp::to_python_value<const element_type&>().get_pytype();
}
#endif
};
};
};
/// result_converter of ReturnInternalStdUniquePtr
struct InternalStdUniquePtrConverter {
template <typename T>
struct apply {
struct type {
typedef typename remove_cvref<T>::type::element_type element_type;
PyObject* operator()(T x) const {
return internal_unique_ptr_to_python(x);
}
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
PyTypeObject const* get_pytype() const {
return bp::to_python_value<const element_type&>().get_pytype();
}
#endif
};
};
};
} // namespace details
/// CallPolicies to get std::unique_ptr value from a function
/// that return an std::unique_ptr.
/// If the object inside the std::unique_ptr is a class or an union
/// it will be moved. In other case, it will be copied.
struct StdUniquePtrCallPolicies : bp::default_call_policies {
typedef details::StdUniquePtrResultConverter result_converter;
};
/// Variant of \see bp::return_internal_reference that extract std::unique_ptr
/// content reference before converting it into a PyObject
struct ReturnInternalStdUniquePtr : bp::return_internal_reference<> {
typedef details::InternalStdUniquePtrConverter result_converter;
template <class ArgumentPackage>
static PyObject* postcall(ArgumentPackage const& args_, PyObject* result) {
// Don't run return_internal_reference postcall on primitive type
if (PyInt_Check(result) || PyBool_Check(result) || PyFloat_Check(result) ||
PyStr_Check(result) || PyComplex_Check(result)) {
return result;
}
return bp::return_internal_reference<>::postcall(args_, result);
}
};
} // namespace eigenpy
namespace boost {
namespace python {
/// Specialize to_python_value for std::unique_ptr
template <typename T>
struct to_python_value<const std::unique_ptr<T>&>
: eigenpy::details::StdUniquePtrResultConverter::apply<
std::unique_ptr<T> >::type {};
} // namespace python
} // namespace boost
#endif // ifndef __eigenpy_utils_std_unique_ptr_hpp__
/// Copyright (c) 2016-2022 CNRS INRIA
///
/// Copyright (c) 2016-2024 CNRS INRIA
/// This file was taken from Pinocchio (header
/// <pinocchio/bindings/python/utils/std-vector.hpp>)
///
......@@ -20,6 +21,7 @@
#include "eigenpy/eigen-to-python.hpp"
#include "eigenpy/pickle-vector.hpp"
#include "eigenpy/registration.hpp"
#include "eigenpy/utils/empty-visitor.hpp"
namespace eigenpy {
// Forward declaration
......@@ -50,7 +52,9 @@ bool from_python_list(PyObject *obj_ptr, T *) {
template <typename vector_type, bool NoProxy>
struct build_list {
static ::boost::python::list run(vector_type &vec) {
static ::boost::python::list run(vector_type &vec, const bool deep_copy) {
if (deep_copy) return build_list<vector_type, true>::run(vec, true);
bp::list bp_list;
for (size_t k = 0; k < vec.size(); ++k) {
bp_list.append(boost::ref(vec[k]));
......@@ -61,13 +65,13 @@ struct build_list {
template <typename vector_type>
struct build_list<vector_type, true> {
static ::boost::python::list run(vector_type &vec) {
static ::boost::python::list run(vector_type &vec, const bool) {
typedef bp::iterator<vector_type> iterator;
return bp::list(iterator()(vec));
}
};
/// \brief Change the behaviour of indexing (method __getitem__ in Python).
/// \brief Change the behavior of indexing (method __getitem__ in Python).
/// This is suitable for container of Eigen matrix objects if you want to mutate
/// them.
template <typename Container>
......@@ -234,6 +238,20 @@ struct reference_arg_from_python<std::vector<Type, Allocator> &>
namespace eigenpy {
namespace details {
/// Defines traits for the container, used in \struct StdContainerFromPythonList
template <class Container>
struct container_traits {
// default behavior expects allocators
typedef typename Container::allocator_type Allocator;
};
template <typename _Tp, std::size_t Size>
struct container_traits<std::array<_Tp, Size> > {
typedef void Allocator;
};
}; // namespace details
///
/// \brief Register the conversion from a Python list to a std::vector
///
......@@ -242,7 +260,7 @@ namespace eigenpy {
template <typename vector_type, bool NoProxy>
struct StdContainerFromPythonList {
typedef typename vector_type::value_type T;
typedef typename vector_type::allocator_type Allocator;
typedef typename details::container_traits<vector_type>::Allocator Allocator;
/// \brief Check if obj_ptr can be converted
static void *convertible(PyObject *obj_ptr) {
......@@ -294,37 +312,23 @@ struct StdContainerFromPythonList {
&convertible, &construct, ::boost::python::type_id<vector_type>());
}
static ::boost::python::list tolist(vector_type &self) {
return details::build_list<vector_type, NoProxy>::run(self);
static ::boost::python::list tolist(vector_type &self,
const bool deep_copy = false) {
return details::build_list<vector_type, NoProxy>::run(self, deep_copy);
}
};
namespace internal {
template <typename T>
struct has_operator_equal
: boost::mpl::if_<typename boost::is_base_of<Eigen::EigenBase<T>, T>::type,
has_operator_equal<Eigen::EigenBase<T> >,
boost::true_type>::type {};
template <typename T, class A>
struct has_operator_equal<std::vector<T, A> > : has_operator_equal<T> {};
template <>
struct has_operator_equal<bool> : boost::true_type {};
template <typename EigenObject>
struct has_operator_equal<Eigen::EigenBase<EigenObject> >
: has_operator_equal<typename EigenObject::Scalar> {};
template <typename T, bool has_operator_equal_value = boost::is_base_of<
boost::true_type, has_operator_equal<T> >::value>
template <typename T,
bool has_operator_equal_value =
std::is_base_of<std::true_type, has_operator_equal<T> >::value>
struct contains_algo;
template <typename T>
struct contains_algo<T, true> {
template <class Container, typename key_type>
static bool run(Container &container, key_type const &key) {
static bool run(const Container &container, key_type const &key) {
return std::find(container.begin(), container.end(), key) !=
container.end();
}
......@@ -333,7 +337,7 @@ struct contains_algo<T, true> {
template <typename T>
struct contains_algo<T, false> {
template <class Container, typename key_type>
static bool run(Container &container, key_type const &key) {
static bool run(const Container &container, key_type const &key) {
for (size_t k = 0; k < container.size(); ++k) {
if (&container[k] == &key) return true;
}
......@@ -352,34 +356,73 @@ struct contains_vector_derived_policies
return contains_algo<key_type>::run(container, key);
}
};
///
/// \brief Add standard method to a std::vector.
/// \tparam NoProxy When set to false, the elements will be copied when
/// returned to Python.
///
template <typename Container, bool NoProxy, typename CoVisitor>
struct ExposeStdMethodToStdVector
: public boost::python::def_visitor<
ExposeStdMethodToStdVector<Container, NoProxy, CoVisitor> > {
typedef StdContainerFromPythonList<Container, NoProxy>
FromPythonListConverter;
ExposeStdMethodToStdVector(const CoVisitor &co_visitor)
: m_co_visitor(co_visitor) {}
template <class Class>
void visit(Class &cl) const {
cl.def(m_co_visitor)
.def("tolist", &FromPythonListConverter::tolist,
(bp::arg("self"), bp::arg("deep_copy") = false),
"Returns the std::vector as a Python list.")
.def("reserve", &Container::reserve,
(bp::arg("self"), bp::arg("new_cap")),
"Increase the capacity of the vector to a value that's greater "
"or equal to new_cap.")
.def(CopyableVisitor<Container>());
}
const CoVisitor &m_co_visitor;
};
/// Helper to ease ExposeStdMethodToStdVector construction
template <typename Container, bool NoProxy, typename CoVisitor>
static ExposeStdMethodToStdVector<Container, NoProxy, CoVisitor>
createExposeStdMethodToStdVector(const CoVisitor &co_visitor) {
return ExposeStdMethodToStdVector<Container, NoProxy, CoVisitor>(co_visitor);
}
} // namespace internal
struct EmptyPythonVisitor
: public ::boost::python::def_visitor<EmptyPythonVisitor> {
template <class classT>
void visit(classT &) const {}
namespace internal {
template <typename vector_type, bool T_picklable = false>
struct def_pickle_std_vector {
static void run(bp::class_<vector_type> &) {}
};
template <typename vector_type>
struct def_pickle_std_vector<vector_type, true> {
static void run(bp::class_<vector_type> &cl) {
cl.def_pickle(PickleVector<vector_type>());
}
};
} // namespace internal
///
/// \brief Expose an std::vector from a type given as template argument.
///
/// \tparam T Type to expose as std::vector<T>.
/// \tparam Allocator Type for the Allocator in std::vector<T,Allocator>.
/// \tparam NoProxy When set to false, the elements will be copied when returned
/// to Python. \tparam EnableFromPythonListConverter Enables the conversion from
/// a Python list to a std::vector<T,Allocator>
///
/// \sa StdAlignedVectorPythonVisitor
/// \tparam vector_type std::vector type to expose
/// \tparam NoProxy When set to false, the elements will be copied when
/// returned to Python.
/// \tparam EnableFromPythonListConverter Enables the
/// conversion from a Python list to a std::vector<T,Allocator>
///
template <class vector_type, bool NoProxy = false,
bool EnableFromPythonListConverter = true>
struct StdVectorPythonVisitor
: public ::boost::python::vector_indexing_suite<
vector_type, NoProxy,
internal::contains_vector_derived_policies<vector_type, NoProxy> >,
public StdContainerFromPythonList<vector_type, NoProxy> {
bool EnableFromPythonListConverter = true, bool pickable = true>
struct StdVectorPythonVisitor {
typedef typename vector_type::value_type value_type;
typedef typename vector_type::allocator_type allocator_type;
typedef StdContainerFromPythonList<vector_type, NoProxy>
FromPythonListConverter;
......@@ -388,40 +431,46 @@ struct StdVectorPythonVisitor
expose(class_name, doc_string, EmptyPythonVisitor());
}
template <typename VisitorDerived>
static void expose(
const std::string &class_name,
const boost::python::def_visitor<VisitorDerived> &visitor) {
template <typename DerivedVisitor>
static void expose(const std::string &class_name,
const bp::def_visitor<DerivedVisitor> &visitor) {
expose(class_name, "", visitor);
}
template <typename VisitorDerived>
static void expose(
const std::string &class_name, const std::string &doc_string,
const boost::python::def_visitor<VisitorDerived> &visitor) {
if (!register_symbolic_link_to_registered_type<vector_type>()) {
template <typename DerivedVisitor>
static void expose(const std::string &class_name,
const std::string &doc_string,
const bp::def_visitor<DerivedVisitor> &visitor) {
// Apply visitor on already registered type or if type is not already
// registered, we define and apply the visitor on it
auto add_std_visitor =
internal::createExposeStdMethodToStdVector<vector_type, NoProxy>(
visitor);
if (!register_symbolic_link_to_registered_type<vector_type>(
add_std_visitor)) {
bp::class_<vector_type> cl(class_name.c_str(), doc_string.c_str());
cl.def(StdVectorPythonVisitor())
cl.def(IdVisitor<vector_type>());
.def(bp::init<size_t, const value_type &>(
bp::args("self", "size", "value"),
"Constructor from a given size and a given value."))
// Standard vector indexing definition
boost::python::vector_indexing_suite<
vector_type, NoProxy,
internal::contains_vector_derived_policies<vector_type, NoProxy> >
vector_indexing;
cl.def(bp::init<size_t, const value_type &>(
bp::args("self", "size", "value"),
"Constructor from a given size and a given value."))
.def(bp::init<const vector_type &>(bp::args("self", "other"),
"Copy constructor"))
.def("tolist", &FromPythonListConverter::tolist, bp::arg("self"),
"Returns the std::vector as a Python list.")
.def(visitor)
.def("reserve", &vector_type::reserve,
(bp::arg("self"), bp::arg("new_cap")),
"Increase the capacity of the vector to a value that's greater "
"or equal to new_cap.")
.def_pickle(PickleVector<vector_type>())
.def(CopyableVisitor<vector_type>());
.def(vector_indexing)
.def(add_std_visitor);
internal::def_pickle_std_vector<vector_type, pickable>::run(cl);
}
if (EnableFromPythonListConverter) {
// Register conversion
if (EnableFromPythonListConverter)
FromPythonListConverter::register_converter();
FromPythonListConverter::register_converter();
}
}
};
......@@ -431,12 +480,12 @@ struct StdVectorPythonVisitor
*/
void EIGENPY_DLLAPI exposeStdVector();
template <typename MatType>
template <typename MatType, typename Alloc = Eigen::aligned_allocator<MatType> >
void exposeStdVectorEigenSpecificType(const char *name) {
typedef std::vector<MatType, Eigen::aligned_allocator<MatType> > VecMatType;
typedef std::vector<MatType, Alloc> VecMatType;
std::string full_name = "StdVec_";
full_name += name;
StdVectorPythonVisitor<VecMatType, false>::expose(
StdVectorPythonVisitor<VecMatType>::expose(
full_name.c_str(),
details::overload_base_get_item_for_std_vector<VecMatType>());
}
......