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 10107 additions and 189 deletions
/// 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_) {
namespace bp = ::boost::python;
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_) {
namespace bp = ::boost::python;
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();
}
};
template <typename Container>
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
......@@ -31,8 +33,6 @@ namespace details {
/// \brief Check if a PyObject can be converted to an std::vector<T>.
template <typename T>
bool from_python_list(PyObject *obj_ptr, T *) {
namespace bp = ::boost::python;
// Check if it is a list
if (!PyList_Check(obj_ptr)) return false;
......@@ -52,8 +52,8 @@ 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) {
namespace bp = ::boost::python;
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) {
......@@ -65,15 +65,13 @@ struct build_list {
template <typename vector_type>
struct build_list<vector_type, true> {
static ::boost::python::list run(vector_type &vec) {
namespace bp = ::boost::python;
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>
......@@ -92,8 +90,6 @@ struct overload_base_get_item_for_std_vector
private:
static boost::python::object base_get_item(
boost::python::back_reference<Container &> container, PyObject *i_) {
namespace bp = ::boost::python;
index_type idx = convert_index(container.get(), i_);
typename Container::iterator i = container.get().begin();
std::advance(i, idx);
......@@ -109,7 +105,6 @@ struct overload_base_get_item_for_std_vector
}
static index_type convert_index(Container &container, PyObject *i_) {
namespace bp = boost::python;
bp::extract<long> i(i_);
if (i.check()) {
long index = i();
......@@ -243,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
///
......@@ -251,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) {
......@@ -279,8 +288,6 @@ struct StdContainerFromPythonList {
static void construct(
PyObject *obj_ptr,
boost::python::converter::rvalue_from_python_stage1_data *memory) {
namespace bp = boost::python;
// Extract the list
bp::object bp_obj(bp::handle<>(bp::borrowed(obj_ptr)));
bp::list bp_list(bp_obj);
......@@ -305,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();
}
......@@ -344,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;
}
......@@ -363,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;
......@@ -399,42 +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) {
namespace bp = boost::python;
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();
}
}
};
......@@ -444,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>());
}
......
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2019, INRIA
* Copyright 2018-2023, INRIA
*/
#ifndef __eigenpy_stride_hpp__
#define __eigenpy_stride_hpp__
#include <Eigen/Core>
#include <eigenpy/fwd.hpp>
namespace eigenpy {
template <typename MatType, int InnerStride = Eigen::Dynamic,
int OuterStride = Eigen::Dynamic,
template <typename MatType, int InnerStride, int OuterStride,
bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime>
struct StrideType {
struct stride_type_matrix {
typedef Eigen::Stride<OuterStride, InnerStride> type;
};
template <typename MatType, int InnerStride, int OuterStride>
struct StrideType<MatType, InnerStride, OuterStride, true> {
struct stride_type_matrix<MatType, InnerStride, OuterStride, true> {
typedef Eigen::InnerStride<InnerStride> type;
};
template <typename EigenType, int InnerStride, int OuterStride,
typename BaseType = typename get_eigen_base_type<EigenType>::type>
struct stride_type;
template <typename MatrixType, int InnerStride, int OuterStride>
struct stride_type<MatrixType, InnerStride, OuterStride,
Eigen::MatrixBase<MatrixType> > {
typedef
typename stride_type_matrix<MatrixType, InnerStride, OuterStride>::type
type;
};
template <typename MatrixType, int InnerStride, int OuterStride>
struct stride_type<const MatrixType, InnerStride, OuterStride,
const Eigen::MatrixBase<MatrixType> > {
typedef typename stride_type_matrix<const MatrixType, InnerStride,
OuterStride>::type type;
};
#ifdef EIGENPY_WITH_TENSOR_SUPPORT
template <typename TensorType, int InnerStride, int OuterStride>
struct stride_type<TensorType, InnerStride, OuterStride,
Eigen::TensorBase<TensorType> > {
typedef Eigen::Stride<OuterStride, InnerStride> type;
};
template <typename TensorType, int InnerStride, int OuterStride>
struct stride_type<const TensorType, InnerStride, OuterStride,
const Eigen::TensorBase<TensorType> > {
typedef Eigen::Stride<OuterStride, InnerStride> type;
};
#endif
template <typename EigenType, int InnerStride = Eigen::Dynamic,
int OuterStride = Eigen::Dynamic>
struct StrideType {
typedef typename stride_type<EigenType, InnerStride, OuterStride>::type type;
};
} // namespace eigenpy
#endif // ifndef __eigenpy_stride_hpp__
//
// Copyright (c) 2023 INRIA
//
#ifndef __eigenpy_tensor_eigen_from_python_hpp__
#define __eigenpy_tensor_eigen_from_python_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/eigen-allocator.hpp"
#include "eigenpy/numpy-type.hpp"
#include "eigenpy/scalar-conversion.hpp"
namespace eigenpy {
template <typename TensorType>
struct expected_pytype_for_arg<TensorType, Eigen::TensorBase<TensorType> > {
static PyTypeObject const *get_pytype() {
PyTypeObject const *py_type = eigenpy::getPyArrayType();
return py_type;
}
};
} // namespace eigenpy
namespace boost {
namespace python {
namespace converter {
template <typename Scalar, int Rank, int Options, typename IndexType>
struct expected_pytype_for_arg<Eigen::Tensor<Scalar, Rank, Options, IndexType> >
: eigenpy::expected_pytype_for_arg<
Eigen::Tensor<Scalar, Rank, Options, IndexType> > {};
template <typename Scalar, int Rank, int Options, typename IndexType>
struct rvalue_from_python_data<
Eigen::Tensor<Scalar, Rank, Options, IndexType> const &>
: ::eigenpy::rvalue_from_python_data<
Eigen::Tensor<Scalar, Rank, Options, IndexType> const &> {
typedef Eigen::Tensor<Scalar, Rank, Options, IndexType> T;
EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(T const &)
};
template <typename Derived>
struct rvalue_from_python_data<Eigen::TensorBase<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 TensorType>
struct eigen_from_py_impl<TensorType, Eigen::TensorBase<TensorType> > {
typedef typename TensorType::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 TensorType>
void *
eigen_from_py_impl<TensorType, Eigen::TensorBase<TensorType> >::convertible(
PyObject *pyObj) {
if (!call_PyArray_Check(reinterpret_cast<PyObject *>(pyObj))) return 0;
typedef typename Eigen::internal::traits<TensorType>::Index Index;
static const Index NumIndices = TensorType::NumIndices;
PyArrayObject *pyArray = reinterpret_cast<PyArrayObject *>(pyObj);
if (!np_type_is_convertible_into_scalar<Scalar>(
EIGENPY_GET_PY_ARRAY_TYPE(pyArray)))
return 0;
if (!(PyArray_NDIM(pyArray) == NumIndices || NumIndices == Eigen::Dynamic))
return 0;
#ifdef NPY_1_8_API_VERSION
if (!(PyArray_FLAGS(pyArray)))
#else
if (!(PyArray_FLAGS(pyArray) & NPY_ALIGNED))
#endif
{
return 0;
}
return pyArray;
}
template <typename TensorType>
void eigen_from_py_impl<TensorType, Eigen::TensorBase<TensorType> >::construct(
PyObject *pyObj, bp::converter::rvalue_from_python_stage1_data *memory) {
eigen_from_py_construct<TensorType>(pyObj, memory);
}
template <typename TensorType>
void eigen_from_py_impl<TensorType,
Eigen::TensorBase<TensorType> >::registration() {
bp::converter::registry::push_back(
reinterpret_cast<void *(*)(_object *)>(&eigen_from_py_impl::convertible),
&eigen_from_py_impl::construct, bp::type_id<TensorType>()
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
,
&eigenpy::expected_pytype_for_arg<TensorType>::get_pytype
#endif
);
}
template <typename TensorType>
struct eigen_from_py_converter_impl<TensorType,
Eigen::TensorBase<TensorType> > {
static void registration() {
EigenFromPy<TensorType>::registration();
// Add conversion to Eigen::TensorBase<TensorType>
typedef Eigen::TensorBase<TensorType> TensorBase;
EigenFromPy<TensorBase>::registration();
// Add conversion to Eigen::TensorRef<TensorType>
typedef Eigen::TensorRef<TensorType> RefType;
EigenFromPy<RefType>::registration();
// Add conversion to Eigen::TensorRef<const TensorType>
typedef const Eigen::TensorRef<const TensorType> ConstRefType;
EigenFromPy<ConstRefType>::registration();
}
};
template <typename TensorType>
struct EigenFromPy<Eigen::TensorBase<TensorType> > : EigenFromPy<TensorType> {
typedef EigenFromPy<TensorType> EigenFromPyDerived;
typedef Eigen::TensorBase<TensorType> 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<TensorType>::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_tensor_eigen_from_python_hpp__
///
/// Copyright (c) 2024 INRIA
///
#ifndef __eigenpy_type_info_hpp__
#define __eigenpy_type_info_hpp__
#include "eigenpy/fwd.hpp"
#include <boost/type_index.hpp>
#include <typeinfo>
#include <typeindex>
namespace eigenpy {
template <typename T>
boost::typeindex::type_index type_info(const T& value) {
return boost::typeindex::type_id_runtime(value);
}
template <typename T>
void expose_boost_type_info() {
boost::python::def(
"type_info",
+[](const T& value) -> boost::typeindex::type_index {
return boost::typeindex::type_id_runtime(value);
},
bp::arg("value"),
"Returns information of the type of value as a "
"boost::typeindex::type_index (can work without RTTI).");
boost::python::def(
"boost_type_info",
+[](const T& value) -> boost::typeindex::type_index {
return boost::typeindex::type_id_runtime(value);
},
bp::arg("value"),
"Returns information of the type of value as a "
"boost::typeindex::type_index (can work without RTTI).");
}
template <typename T>
void expose_std_type_info() {
boost::python::def(
"std_type_info",
+[](const T& value) -> std::type_index { return typeid(value); },
bp::arg("value"),
"Returns information of the type of value as a std::type_index.");
}
///
/// \brief Add the Python method type_info to query information of a type.
///
template <class C>
struct TypeInfoVisitor : public bp::def_visitor<TypeInfoVisitor<C> > {
template <class PyClass>
void visit(PyClass& cl) const {
cl.def("type_info", &boost_type_info, bp::arg("self"),
"Queries information of the type of *this as a "
"boost::typeindex::type_index (can work without RTTI).");
cl.def("boost_type_info", &boost_type_info, bp::arg("self"),
"Queries information of the type of *this as a "
"boost::typeindex::type_index (can work without RTTI).");
cl.def("std_type_info", &std_type_info, bp::arg("self"),
"Queries information of the type of *this as a std::type_index.");
}
private:
static boost::typeindex::type_index boost_type_info(const C& self) {
return boost::typeindex::type_id_runtime(self);
}
static std::type_index std_type_info(const C& self) { return typeid(self); }
};
} // namespace eigenpy
#endif // __eigenpy_type_info_hpp__
//
// Copyright (c) 2020-2021 INRIA
// Copyright (c) 2020-2025 INRIA
// code aptapted from
// https://github.com/numpy/numpy/blob/41977b24ae011a51f64faa75cb524c7350fdedd9/numpy/core/src/umath/_rational_tests.c.src
//
......@@ -9,6 +9,7 @@
#include "eigenpy/register.hpp"
#include "eigenpy/user-type.hpp"
#include "eigenpy/utils/python-compat.hpp"
namespace eigenpy {
namespace internal {
......@@ -150,6 +151,7 @@ EIGENPY_REGISTER_BINARY_OPERATOR(greater_equal, >=)
}
EIGENPY_REGISTER_UNARY_OPERATOR(negative, -)
EIGENPY_REGISTER_UNARY_OPERATOR(square, x *)
} // namespace internal
......@@ -207,11 +209,7 @@ void registerCommonUfunc() {
const int type_code = Register::getTypeCode<Scalar>();
PyObject *numpy_str;
#if PY_MAJOR_VERSION >= 3
numpy_str = PyUnicode_FromString("numpy");
#else
numpy_str = PyString_FromString("numpy");
#endif
numpy_str = PyStr_FromString("numpy");
PyObject *numpy;
numpy = PyImport_Import(numpy_str);
Py_DECREF(numpy_str);
......@@ -261,6 +259,7 @@ void registerCommonUfunc() {
// Unary operators
EIGENPY_REGISTER_UNARY_UFUNC(negative, type_code, Scalar, Scalar);
EIGENPY_REGISTER_UNARY_UFUNC(square, type_code, Scalar, Scalar);
Py_DECREF(numpy);
}
......
......@@ -132,34 +132,43 @@ struct SpecialMethods<T, NPY_USERDEF> {
eigenpy::Exception("Cannot retrieve the type stored in the array.");
return -1;
}
PyArrayObject* py_array = static_cast<PyArrayObject*>(array);
PyArray_Descr* descr = PyArray_DTYPE(py_array);
PyTypeObject* array_scalar_type = descr->typeobj;
PyTypeObject* src_obj_type = Py_TYPE(src_obj);
T& dest = *static_cast<T*>(dest_ptr);
if (array_scalar_type != src_obj_type) {
std::stringstream ss;
ss << "The input type is of wrong type. ";
ss << "The expected type is " << bp::type_info(typeid(T)).name()
<< std::endl;
eigenpy::Exception(ss.str());
return -1;
}
long long src_value = PyLong_AsLongLong(src_obj);
if (src_value == -1 && PyErr_Occurred()) {
std::stringstream ss;
ss << "The input type is of wrong type. ";
ss << "The expected type is " << bp::type_info(typeid(T)).name()
<< std::endl;
eigenpy::Exception(ss.str());
return -1;
}
dest = T(src_value);
bp::extract<T&> extract_src_obj(src_obj);
if (!extract_src_obj.check()) {
std::stringstream ss;
ss << "The input type is of wrong type. ";
ss << "The expected type is " << bp::type_info(typeid(T)).name()
<< std::endl;
eigenpy::Exception(ss.str());
return -1;
} else {
bp::extract<T&> extract_src_obj(src_obj);
if (!extract_src_obj.check()) {
std::cout << "if (!extract_src_obj.check())" << std::endl;
std::stringstream ss;
ss << "The input type is of wrong type. ";
ss << "The expected type is " << bp::type_info(typeid(T)).name()
<< std::endl;
eigenpy::Exception(ss.str());
return -1;
}
const T& src = extract_src_obj();
T& dest = *static_cast<T*>(dest_ptr);
dest = src;
}
const T& src = extract_src_obj();
T& dest = *static_cast<T*>(dest_ptr);
dest = src;
return 0;
}
......@@ -171,7 +180,8 @@ struct SpecialMethods<T, NPY_USERDEF> {
char* srcptr = static_cast<char*>(src);
PyArrayObject* py_array = static_cast<PyArrayObject*>(array);
PyArray_CopySwapFunc* copyswap = PyArray_DESCR(py_array)->f->copyswap;
PyArray_CopySwapFunc* copyswap =
PyDataType_GetArrFuncs(PyArray_DESCR(py_array))->copyswap;
for (npy_intp i = 0; i < n; i++) {
copyswap(dstptr, srcptr, swap, array);
......@@ -189,8 +199,8 @@ struct SpecialMethods<T, NPY_USERDEF> {
return (npy_bool)(value != ZeroValue);
} else {
T tmp_value;
PyArray_DESCR(py_array)->f->copyswap(
&tmp_value, ip, PyArray_ISBYTESWAPPED(py_array), array);
PyDataType_GetArrFuncs(PyArray_DESCR(py_array))
->copyswap(&tmp_value, ip, PyArray_ISBYTESWAPPED(py_array), array);
return (npy_bool)(tmp_value != ZeroValue);
}
}
......@@ -286,7 +296,6 @@ bool registerCast(const bool safe) {
template <typename T>
boost::python::object getInstanceClass() {
// Query into the registry for type T.
namespace bp = boost::python;
bp::type_info type = bp::type_id<T>();
const bp::converter::registration* registration =
bp::converter::registry::query(type);
......
#ifndef __eigenpy_utils_empty_visitor_hpp__
#define __eigenpy_utils_empty_visitor_hpp__
#include <boost/python.hpp>
namespace eigenpy {
struct EmptyPythonVisitor
: public ::boost::python::def_visitor<EmptyPythonVisitor> {
template <class classT>
void visit(classT &) const {}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_utils_empty_visitor_hpp__
//
// Copyright (c) 2020 INRIA
// Copyright (c) 2020-2023 INRIA
//
#ifndef __eigenpy_utils_is_aligned_hpp__
#define __eigenpy_utils_is_aligned_hpp__
namespace eigenpy {
inline bool is_aligned(void* ptr, std::size_t alignment) {
inline bool is_aligned(const void* ptr, std::size_t alignment) {
return (reinterpret_cast<std::size_t>(ptr) & (alignment - 1)) == 0;
}
} // namespace eigenpy
......
/*
* Copyright 2020 INRIA
* Copyright 2020-2024 INRIA
*/
#ifndef __eigenpy_utils_scalar_is_approx_hpp__
#define __eigenpy_utils_scalar_is_approx_hpp__
#ifndef __eigenpy_utils_is_approx_hpp__
#define __eigenpy_utils_is_approx_hpp__
#include <Eigen/Core>
#include <Eigen/SparseCore>
namespace eigenpy {
template <typename MatrixType1, typename MatrixType2>
inline EIGEN_DONT_INLINE bool is_approx(
const Eigen::MatrixBase<MatrixType1>& mat1,
const Eigen::MatrixBase<MatrixType2>& mat2,
const typename MatrixType1::Scalar& prec) {
EIGEN_DONT_INLINE bool is_approx(const Eigen::MatrixBase<MatrixType1>& mat1,
const Eigen::MatrixBase<MatrixType2>& mat2,
const typename MatrixType1::RealScalar& prec) {
return mat1.isApprox(mat2, prec);
}
template <typename MatrixType1, typename MatrixType2>
inline EIGEN_DONT_INLINE bool is_approx(
const Eigen::MatrixBase<MatrixType1>& mat1,
const Eigen::MatrixBase<MatrixType2>& mat2) {
EIGEN_DONT_INLINE bool is_approx(const Eigen::MatrixBase<MatrixType1>& mat1,
const Eigen::MatrixBase<MatrixType2>& mat2) {
return is_approx(
mat1, mat2,
Eigen::NumTraits<typename MatrixType1::Scalar>::dummy_precision());
Eigen::NumTraits<typename MatrixType1::RealScalar>::dummy_precision());
}
template <typename MatrixType1, typename MatrixType2>
EIGEN_DONT_INLINE bool is_approx(
const Eigen::SparseMatrixBase<MatrixType1>& mat1,
const Eigen::SparseMatrixBase<MatrixType2>& mat2,
const typename MatrixType1::RealScalar& prec) {
return mat1.isApprox(mat2, prec);
}
template <typename MatrixType1, typename MatrixType2>
EIGEN_DONT_INLINE bool is_approx(
const Eigen::SparseMatrixBase<MatrixType1>& mat1,
const Eigen::SparseMatrixBase<MatrixType2>& mat2) {
return is_approx(
mat1, mat2,
Eigen::NumTraits<typename MatrixType1::RealScalar>::dummy_precision());
}
} // namespace eigenpy
#endif // ifndef __eigenpy_utils_scalar_is_approx_hpp__
#endif // ifndef __eigenpy_utils_is_approx_hpp__
//
// Copyright (c) 2024 INRIA
//
//
#ifndef __eigenpy_utils_python_compat_hpp__
#define __eigenpy_utils_python_compat_hpp__
#if PY_MAJOR_VERSION >= 3
#define PyInt_Check PyLong_Check
#define PyStr_Check PyUnicode_Check
#define PyStr_FromString PyUnicode_FromString
#else
#define PyStr_Check PyString_Check
#define PyStr_FromString PyString_FromString
#endif
#endif // ifndef __eigenpy_utils_python_compat_hpp__
//
// Copyright (c) 2024 INRIA
//
//
#ifndef __eigenpy_utils_traits_hpp__
#define __eigenpy_utils_traits_hpp__
#include <type_traits>
#include <string>
#include <complex>
namespace eigenpy {
namespace details {
/// Trait to remove const&
template <typename T>
struct remove_cvref : std::remove_cv<typename std::remove_reference<T>::type> {
};
/// Trait to detect if T is a class or an union
template <typename T>
struct is_class_or_union
: std::integral_constant<bool, std::is_class<T>::value ||
std::is_union<T>::value> {};
/// trait to detect if T is a std::complex managed by Boost Python
template <typename T>
struct is_python_complex : std::false_type {};
/// From boost/python/converter/builtin_converters
template <>
struct is_python_complex<std::complex<float> > : std::true_type {};
template <>
struct is_python_complex<std::complex<double> > : std::true_type {};
template <>
struct is_python_complex<std::complex<long double> > : std::true_type {};
template <typename T>
struct is_python_primitive_type_helper
: std::integral_constant<bool, !is_class_or_union<T>::value ||
std::is_same<T, std::string>::value ||
std::is_same<T, std::wstring>::value ||
is_python_complex<T>::value> {};
/// Trait to detect if T is a Python primitive type
template <typename T>
struct is_python_primitive_type
: is_python_primitive_type_helper<typename remove_cvref<T>::type> {};
} // namespace details
} // namespace eigenpy
#endif // ifndef __eigenpy_utils_traits_hpp__
//
// Copyright (c) 2024 INRIA
//
#ifndef __eigenpy_utils_variant_hpp__
#define __eigenpy_utils_variant_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/utils/traits.hpp"
#include "eigenpy/utils/python-compat.hpp"
#include <boost/python.hpp>
#include <boost/variant.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/vector.hpp>
#include <type_traits>
#ifdef EIGENPY_WITH_CXX17_SUPPORT
#include <variant>
#endif
namespace eigenpy {
namespace details {
/// Allow to use std::variant and boost::variant with the same API
template <typename ResultType, typename Variant>
struct VariantVisitorType {};
/// Allow to get all alternatives in a boost::mpl vector
template <typename Variant>
struct VariantAlternatives {};
template <typename Variant>
struct empty_variant {};
template <typename T>
struct is_empty_variant : std::false_type {};
#ifdef EIGENPY_WITH_CXX17_SUPPORT
/// std::variant implementation
template <typename ResultType, typename... Alternatives>
struct VariantVisitorType<ResultType, std::variant<Alternatives...> > {
typedef std::variant<Alternatives...> variant_type;
typedef ResultType result_type;
template <typename Visitor, typename Visitable>
static result_type visit(Visitor&& visitor, Visitable&& v) {
return std::visit(std::forward<Visitor>(visitor),
std::forward<Visitable>(v));
}
result_type operator()(std::monostate) const {
return bp::incref(bp::object().ptr()); // None
}
};
template <typename... Alternatives>
struct VariantAlternatives<std::variant<Alternatives...> > {
typedef boost::mpl::vector<Alternatives...> types;
};
template <typename... Alternatives>
struct empty_variant<std::variant<Alternatives...> > {
typedef std::monostate type;
};
template <>
struct is_empty_variant<std::monostate> : std::true_type {};
#endif
/// boost::variant implementation
template <typename ResultType, typename... Alternatives>
struct VariantVisitorType<ResultType, boost::variant<Alternatives...> >
: boost::static_visitor<ResultType> {
typedef boost::variant<Alternatives...> variant_type;
typedef ResultType result_type;
template <typename Visitor, typename Visitable>
static result_type visit(Visitor&& visitor, Visitable&& visitable) {
return std::forward<Visitable>(visitable).apply_visitor(visitor);
}
result_type operator()(boost::blank) const {
return bp::incref(bp::object().ptr()); // None
}
};
template <typename... Alternatives>
struct VariantAlternatives<boost::variant<Alternatives...> > {
typedef typename boost::variant<Alternatives...>::types types;
};
template <typename... Alternatives>
struct empty_variant<boost::variant<Alternatives...> > {
typedef boost::blank type;
};
template <>
struct is_empty_variant<boost::blank> : std::true_type {};
/// Convert None to a {boost,std}::variant with boost::blank or std::monostate
/// value
template <typename Variant>
struct EmptyConvertible {
static void registration() {
bp::converter::registry::push_back(convertible, construct,
bp::type_id<Variant>());
}
// convertible only for None
static void* convertible(PyObject* obj) {
return (obj == Py_None) ? obj : nullptr;
};
// construct in place
static void construct(PyObject*,
bp::converter::rvalue_from_python_stage1_data* data) {
void* storage =
reinterpret_cast<bp::converter::rvalue_from_python_storage<Variant>*>(
data)
->storage.bytes;
new (storage) Variant(typename empty_variant<Variant>::type());
data->convertible = storage;
};
};
/// Implement convertible and expected_pytype for bool, integer and float
template <typename T, class Enable = void>
struct NumericConvertibleImpl {};
template <typename T>
struct NumericConvertibleImpl<
T, typename std::enable_if<std::is_same<T, bool>::value>::type> {
static void* convertible(PyObject* obj) {
return PyBool_Check(obj) ? obj : nullptr;
}
static PyTypeObject const* expected_pytype() { return &PyBool_Type; }
};
template <typename T>
struct NumericConvertibleImpl<
T, typename std::enable_if<!std::is_same<T, bool>::value &&
std::is_integral<T>::value>::type> {
static void* convertible(PyObject* obj) {
// PyLong return true for bool type
return (PyInt_Check(obj) && !PyBool_Check(obj)) ? obj : nullptr;
}
static PyTypeObject const* expected_pytype() { return &PyLong_Type; }
};
template <typename T>
struct NumericConvertibleImpl<
T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
static void* convertible(PyObject* obj) {
return PyFloat_Check(obj) ? obj : nullptr;
}
static PyTypeObject const* expected_pytype() { return &PyFloat_Type; }
};
/// Convert numeric type to Variant without ambiguity
template <typename T, typename Variant>
struct NumericConvertible {
static void registration() {
bp::converter::registry::push_back(
&convertible, &bp::converter::implicit<T, Variant>::construct,
bp::type_id<Variant>()
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
,
&expected_pytype
#endif
);
}
static void* convertible(PyObject* obj) {
return NumericConvertibleImpl<T>::convertible(obj);
}
static PyTypeObject const* expected_pytype() {
return NumericConvertibleImpl<T>::expected_pytype();
}
};
/// Convert {boost,std}::variant<class...> alternative to a Python object.
/// This converter copy the alternative.
template <typename Variant>
struct VariantValueToObject : VariantVisitorType<PyObject*, Variant> {
typedef VariantVisitorType<PyObject*, Variant> Base;
typedef typename Base::result_type result_type;
typedef typename Base::variant_type variant_type;
static result_type convert(const variant_type& v) {
return Base::visit(VariantValueToObject(), v);
}
template <typename T>
result_type operator()(T& t) const {
return bp::incref(bp::object(t).ptr());
}
using Base::operator();
};
/// Convert {boost,std}::variant<class...> alternative reference to a Python
/// object. This converter return the alternative reference. The code that
/// create the reference holder is taken from \see
/// bp::to_python_indirect.
template <typename Variant>
struct VariantRefToObject : VariantVisitorType<PyObject*, Variant> {
typedef VariantVisitorType<PyObject*, Variant> Base;
typedef typename Base::result_type result_type;
typedef typename Base::variant_type variant_type;
static result_type convert(const variant_type& v) {
return Base::visit(VariantRefToObject(), v);
}
template <typename T,
typename std::enable_if<is_python_primitive_type<T>::value,
bool>::type = true>
result_type operator()(T t) const {
return bp::incref(bp::object(t).ptr());
}
template <typename T,
typename std::enable_if<!is_python_primitive_type<T>::value,
bool>::type = true>
result_type operator()(T& t) const {
return bp::detail::make_reference_holder::execute(&t);
}
/// Copy the object when it's None
using Base::operator();
};
/// Converter used in \see ReturnInternalVariant.
/// This is inspired by \see bp::reference_existing_object.
/// It will call \see VariantRefToObject to extract the alternative
/// reference.
template <typename Variant>
struct VariantConverter {
typedef Variant variant_type;
template <class T>
struct apply {
struct type {
PyObject* operator()(const variant_type& v) const {
return VariantRefToObject<variant_type>::convert(v);
}
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
PyTypeObject const* get_pytype() const {
return bp::converter::registered_pytype<variant_type>::get_pytype();
}
#endif
};
};
};
/// Convert an Alternative type to a Variant
template <typename Variant>
struct VariantConvertible {
typedef Variant variant_type;
template <class T, typename std::enable_if<is_empty_variant<T>::value,
bool>::type = true>
void operator()(T) {
EmptyConvertible<variant_type>::registration();
}
template <class T, typename std::enable_if<!is_empty_variant<T>::value &&
std::is_arithmetic<T>::value,
bool>::type = true>
void operator()(T) {
NumericConvertible<T, variant_type>::registration();
}
template <class T, typename std::enable_if<!is_empty_variant<T>::value &&
!std::is_arithmetic<T>::value,
bool>::type = true>
void operator()(T) {
bp::implicitly_convertible<T, variant_type>();
}
};
} // namespace details
/// Variant of \see bp::return_internal_reference that
/// extract {boost,std}::variant<class...> alternative reference before
/// converting it into a PyObject
template <typename Variant>
struct ReturnInternalVariant : bp::return_internal_reference<> {
typedef Variant variant_type;
typedef details::VariantConverter<variant_type> 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);
}
};
/// Define a defaults converter to convert a {boost,std}::variant alternative to
/// a Python object by copy and to convert implicitly an alternative to a
/// {boost,std}::variant.
///
/// Example:
///
/// typedef boost::variant<Struct1, Struct2> MyVariant;
/// struct VariantHolder {
/// MyVariant variant;
/// };
/// ...
/// void expose() {
/// bp::class_<Struct1>("Struct1", bp::init<>());
/// bp::class_<Struct2>("Struct1", bp::init<>())
/// typedef eigenpy::VariantConverter<MyVariant> Converter;
/// Converter::registration();
///
/// bp::class_<VariantHolder>("VariantHolder", bp::init<>())
/// .add_property("variant",
/// bp::make_getter(&VariantHolder::variant,
/// Converter::return_internal_reference()),
/// bp::make_setter(&VariantHolder::variant));
/// }
template <typename Variant>
struct VariantConverter {
typedef Variant variant_type;
typedef ReturnInternalVariant<variant_type> return_internal_reference;
static void registration() {
typedef details::VariantValueToObject<variant_type> variant_to_value;
typedef typename details::VariantAlternatives<variant_type>::types types;
bp::to_python_converter<variant_type, variant_to_value>();
boost::mpl::for_each<types>(details::VariantConvertible<variant_type>());
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_utils_variant_hpp__
......@@ -18,6 +18,14 @@ namespace eigenpy {
///
std::string EIGENPY_DLLAPI printVersion(const std::string& delimiter = ".");
///
/// \brief Returns the current version of Eigen3 as a string using
/// the following standard:
/// EIGEN_MINOR_VERSION.EIGEN_MINOR_VERSION.EIGEN_PATCH_VERSION
///
std::string EIGENPY_DLLAPI
printEigenVersion(const std::string& delimiter = ".");
///
/// \brief Checks if the current version of EigenPy is at least the version
/// provided
......
<?xml version="1.0"?>
<package format="3">
<name>eigenpy</name>
<version>2.9.0</version>
<version>3.10.3</version>
<description>Bindings between Numpy and Eigen using Boost.Python</description>
<maintainer email="justin.carpentier@inria.fr">Justin Carpentier</maintainer>
<maintainer email="opensource@wolfgangmerkt.com">Wolfgang Merkt</maintainer>
......@@ -20,7 +20,9 @@
<depend condition="$ROS_PYTHON_VERSION == 2">python</depend>
<depend condition="$ROS_PYTHON_VERSION == 3">python3</depend>
<depend condition="$ROS_PYTHON_VERSION == 2">python-numpy</depend>
<depend condition="$ROS_PYTHON_VERSION == 2">python-scipy</depend>
<depend condition="$ROS_PYTHON_VERSION == 3">python3-numpy</depend>
<depend condition="$ROS_PYTHON_VERSION == 3">python3-scipy</depend>
<depend>eigen</depend>
<depend>boost</depend>
......
Source diff could not be displayed: it is too large. Options to address this: view the blob.
[project]
name = "eigenpy"
version = "3.10.3"
description = "Bindings between Numpy and Eigen using Boost.Python"
platforms = ["linux-64", "osx-64", "osx-arm64", "win-64"]
channels = ["conda-forge"]
license = "BSD-2-Clause"
license-file = "LICENSE"
[build-dependencies]
ccache = ">=4.9.1"
cmake = ">=3.10"
cxx-compiler = ">=1.7.0"
ninja = ">=1.11"
pkg-config = ">=0.29.2"
git = ">=2.47.0"
[dependencies]
libboost-devel = ">=1.80.0"
libboost-python-devel = ">=1.80.0"
eigen = ">=3.4.0"
numpy = ">=1.22.0"
python = ">=3.9.0"
scipy = ">=1.10.0"
[activation]
scripts = ["development/scripts//pixi/activation.sh"]
[target.win-64.activation]
scripts = ["development/scripts//pixi/activation.bat"]
[tasks]
# We must avoid to set CMAKE_CXX_FLAGS because of WIN32
# https://discourse.cmake.org/t/strictly-appending-to-cmake-lang-flags/6478
configure = { cmd = [
"CXXFLAGS=$EIGENPY_CXX_FLAGS",
"cmake",
"-G",
"Ninja",
"-B",
"build",
"-S",
".",
"-DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX",
"-DCMAKE_BUILD_TYPE=$EIGENPY_BUILD_TYPE",
"-DGENERATE_PYTHON_STUBS=$EIGENPY_PYTHON_STUBS",
"-DBUILD_WITH_CHOLMOD_SUPPORT=$EIGENPY_CHOLMOD_SUPPORT",
"-DBUILD_WITH_ACCELERATE_SUPPORT=$EIGENPY_ACCELERATE_SUPPORT",
] }
build = { cmd = "cmake --build build --target all", depends-on = ["configure"] }
clean = { cmd = "rm -rf build" }
test = { cmd = "ctest --test-dir build --output-on-failure", depends-on = [
"build",
] }
[feature.lint]
dependencies = { pre-commit = ">=3.6.2" }
tasks = { lint = { cmd = "pre-commit run --all" } }
# Increment the version number with EIGENPY_VERSION variable
[feature.new-version.dependencies]
tomlkit = ">=0.13.2"
[feature.new-version.tasks]
configure_new_version = { cmd = [
"CXXFLAGS=$EIGENPY_CXX_FLAGS",
"cmake",
"-G",
"Ninja",
"-B",
"build_new_version",
"-S",
".",
"-DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX",
"-DCMAKE_BUILD_TYPE=$EIGENPY_BUILD_TYPE",
"-DGENERATE_PYTHON_STUBS=ON",
"-DBUILD_WITH_CHOLMOD_SUPPORT=ON",
"-DBUILD_WITH_ACCELERATE_SUPPORT=OFF",
] }
release_new_version = { cmd = "VERSION=$EIGENPY_VERSION cmake --build build_new_version --target release", depends-on = [
"configure_new_version",
] }
# Cholmod support
[feature.cholmod]
dependencies = { suitesparse = ">=5" }
activation = { env = { EIGENPY_CHOLMOD_SUPPORT = "ON" } }
# Accelerate only work on Apple ARM platform
[feature.accelerate]
[feature.accelerate.target.osx-arm64]
activation = { env = { EIGENPY_ACCELERATE_SUPPORT = "ON" } }
[feature.py312.dependencies]
python = "3.12.*"
[feature.py39.dependencies]
python = "3.9.*"
# Use clang-cl on Windows.
# We must use scripts instead of env to setup CC and CXX
# to avoid cxx-compiler to overwrite them.
[feature.clang-cl]
platforms = ["win-64"]
activation = { scripts = ["development/scripts//pixi/activation_clang_cl.bat"] }
# Use clang on GNU/Linux.
# We must use scripts instead of env to setup CC and CXX
# to avoid cxx-compiler to overwrite them.
[feature.clang]
platforms = ["linux-64"]
activation = { scripts = ["development/scripts//pixi/activation_clang.sh"] }
dependencies = { clangxx = "*" }
[environments]
default = { features = ["py312"], solve-group = "py312" }
clang = { features = ["clang", "py312"] }
lint = { features = ["lint"], solve-group = "py312" }
cholmod = { features = ["cholmod", "py312"], solve-group = "py312" }
accelerate = { features = ["accelerate", "py312"], solve-group = "py312" }
py39 = { features = ["py39"], solve-group = "py39" }
# Accelerate will only work in Eigen next release
all = { features = ["cholmod", "py312"], solve-group = "py312" }
all-py39 = { features = ["cholmod", "py39"], solve-group = "py39" }
all-clang-cl = { features = [
"cholmod",
"clang-cl",
"py312",
], solve-group = "py312" }
# Release a new software version
new-version = { features = [
"new-version",
"cholmod",
"py312",
], solve-group = "py312" }
[tool.ruff]
extend-exclude = ["cmake"]
[tool.ruff.lint]
extend-select = ["I", "NPY", "RUF", "UP", "W"]
[tool.ruff.lint.isort]
known-first-party = ["eigenpy"]
[tool.tomlsort]
all = true