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 2674 additions and 667 deletions
/*
* Copyright 2019, INRIA
* Copyright 2019 INRIA
*/
#ifndef __eigenpy_expose_hpp__
......@@ -7,29 +7,22 @@
#include "eigenpy/registration.hpp"
namespace eigenpy
{
namespace internal
{
///
/// \brief Allows a template specialization.
///
template<typename T>
struct call_expose
{
static inline void run() { T::expose(); }
};
} // namespace internal
///
/// \brief Call the expose function of a given type T.
///
template<typename T>
inline void expose()
{
if(!register_symbolic_link_to_registered_type<T>())
internal::call_expose<T>::run();
}
namespace eigenpy {
///
/// \brief Allows a template specialization.
///
template <typename T>
struct call {
static inline void expose() { T::expose(); }
};
///
/// \brief Call the expose function of a given type T.
///
template <typename T>
inline void expose() {
if (!register_symbolic_link_to_registered_type<T>()) call<T>::expose();
}
} // namespace eigenpy
#endif // ifndef __eigenpy_expose_hpp__
#endif // ifndef __eigenpy_expose_hpp__
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2019, INRIA
* Copyright 2014-2024 CNRS INRIA
*/
#ifndef __eigenpy_fwd_hpp__
#define __eigenpy_fwd_hpp__
#if defined(__clang__)
#define EIGENPY_CLANG_COMPILER
#elif defined(__GNUC__)
#define EIGENPY_GCC_COMPILER
#elif defined(_MSC_VER)
#define EIGENPY_MSVC_COMPILER
#endif
#if (__cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703))
#define EIGENPY_WITH_CXX17_SUPPORT
#endif
#if (__cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201403))
#define EIGENPY_WITH_CXX14_SUPPORT
#endif
#if (__cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600))
#define EIGENPY_WITH_CXX11_SUPPORT
#endif
#define EIGENPY_STRING_LITERAL(string) #string
#define EIGENPY_STRINGIZE(string) EIGENPY_STRING_LITERAL(string)
#define _EIGENPY_PPCAT(A, B) A##B
#define EIGENPY_PPCAT(A, B) _EIGENPY_PPCAT(A, B)
#define EIGENPY_STRINGCAT(A, B) A B
// For more details, visit
// https://stackoverflow.com/questions/171435/portability-of-warning-preprocessor-directive
#if defined(EIGENPY_CLANG_COMPILER) || defined(EIGENPY_GCC_COMPILER)
#define EIGENPY_PRAGMA(x) _Pragma(#x)
#define EIGENPY_PRAGMA_MESSAGE(the_message) \
EIGENPY_PRAGMA(GCC message the_message)
#define EIGENPY_PRAGMA_WARNING(the_message) \
EIGENPY_PRAGMA(GCC warning the_message)
#define EIGENPY_PRAGMA_DEPRECATED(the_message) \
EIGENPY_PRAGMA_WARNING(Deprecated : the_message)
#define EIGENPY_PRAGMA_DEPRECATED_HEADER(old_header, new_header) \
EIGENPY_PRAGMA_WARNING( \
Deprecated header file : #old_header has been replaced \
by #new_header.\n Please use #new_header instead of #old_header.)
#elif defined(WIN32)
#define EIGENPY_PRAGMA(x) __pragma(#x)
#define EIGENPY_PRAGMA_MESSAGE(the_message) \
EIGENPY_PRAGMA(message(#the_message))
#define EIGENPY_PRAGMA_WARNING(the_message) \
EIGENPY_PRAGMA(message(EIGENPY_STRINGCAT("WARNING: ", the_message)))
#endif
#define EIGENPY_DEPRECATED_MACRO(macro, the_message) \
EIGENPY_PRAGMA_WARNING( \
EIGENPY_STRINGCAT("this macro is deprecated: ", the_message))
#define EIGENPY_DEPRECATED_FILE(the_message) \
EIGENPY_PRAGMA_WARNING( \
EIGENPY_STRINGCAT("this file is deprecated: ", the_message))
#define EIGENPY_DOCUMENTATION_START_IGNORE /// \cond
#define EIGENPY_DOCUMENTATION_END_IGNORE /// \endcond
#include "eigenpy/config.hpp"
#include <boost/type_traits/is_base_of.hpp>
// Silence a warning about a deprecated use of boost bind by boost python
// at least fo boost 1.73 to 1.75
// ref. https://github.com/stack-of-tasks/tsid/issues/128
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <boost/python.hpp>
#include <boost/python/scope.hpp>
#include <type_traits>
#include <utility>
namespace eigenpy {
namespace bp = boost::python;
}
#define NO_IMPORT_ARRAY
#include "eigenpy/numpy.hpp"
#undef NO_IMPORT_ARRAY
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <Eigen/Core>
#include <Eigen/Sparse>
#include <Eigen/Geometry>
#include <numpy/numpyconfig.h>
#ifdef NPY_1_8_API_VERSION
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#ifdef EIGENPY_WITH_CXX11_SUPPORT
#include <unsupported/Eigen/CXX11/Tensor>
#define EIGENPY_WITH_TENSOR_SUPPORT
#endif
#include <numpy/noprefix.h>
#if EIGEN_VERSION_AT_LEAST(3, 2, 90)
#define EIGENPY_DEFAULT_ALIGNMENT_VALUE Eigen::Aligned16
#else
#define EIGENPY_DEFAULT_ALIGNMENT_VALUE Eigen::Aligned
#endif
#define EIGENPY_DEFAULT_ALIGN_BYTES EIGEN_DEFAULT_ALIGN_BYTES
#define EIGENPY_NO_ALIGNMENT_VALUE Eigen::Unaligned
#ifdef NPY_ALIGNED
#if EIGEN_VERSION_AT_LEAST(3,2,90)
#define EIGENPY_DEFAULT_ALIGNMENT_VALUE Eigen::Aligned16
#define EIGENPY_UNUSED_VARIABLE(var) (void)(var)
#define EIGENPY_UNUSED_TYPE(type) EIGENPY_UNUSED_VARIABLE((type *)(NULL))
#ifndef NDEBUG
#define EIGENPY_USED_VARIABLE_ONLY_IN_DEBUG_MODE(var)
#else
#define EIGENPY_DEFAULT_ALIGNMENT_VALUE Eigen::Aligned
#define EIGENPY_USED_VARIABLE_ONLY_IN_DEBUG_MODE(var) \
EIGENPY_UNUSED_VARIABLE(var)
#endif
#ifdef EIGENPY_WITH_CXX11_SUPPORT
#include <memory>
#define EIGENPY_SHARED_PTR_HOLDER_TYPE(T) ::std::shared_ptr<T>
#else
#include <boost/shared_ptr.hpp>
#define EIGENPY_SHARED_PTR_HOLDER_TYPE(T) ::boost::shared_ptr<T>
#endif
namespace eigenpy {
// Default Scalar value can't be defined in the declaration
// because of a CL bug.
// See https://github.com/stack-of-tasks/eigenpy/pull/462
template <typename MatType, typename Scalar>
struct EigenToPy;
template <typename MatType, typename Scalar>
struct EigenFromPy;
template <typename T>
struct remove_const_reference {
typedef typename boost::remove_const<
typename boost::remove_reference<T>::type>::type type;
};
template <typename EigenType>
struct get_eigen_base_type {
typedef typename remove_const_reference<EigenType>::type EigenType_;
typedef typename boost::mpl::if_<
boost::is_base_of<Eigen::MatrixBase<EigenType_>, EigenType_>,
Eigen::MatrixBase<EigenType_>,
typename boost::mpl::if_<
boost::is_base_of<Eigen::SparseMatrixBase<EigenType_>, EigenType_>,
Eigen::SparseMatrixBase<EigenType_>
#ifdef EIGENPY_WITH_TENSOR_SUPPORT
,
typename boost::mpl::if_<
boost::is_base_of<Eigen::TensorBase<EigenType_>, EigenType_>,
Eigen::TensorBase<EigenType_>, void>::type
#else
#define EIGENPY_DEFAULT_ALIGNMENT_VALUE Eigen::Unaligned
,
void
#endif
>::type>::type _type;
typedef typename boost::mpl::if_<
boost::is_const<typename boost::remove_reference<EigenType>::type>,
const _type, _type>::type type;
};
template <typename EigenType>
struct get_eigen_plain_type;
template <typename MatType, int Options, typename Stride>
struct get_eigen_plain_type<Eigen::Ref<MatType, Options, Stride> > {
typedef typename Eigen::internal::traits<
Eigen::Ref<MatType, Options, Stride> >::PlainObjectType type;
};
#ifdef EIGENPY_WITH_TENSOR_SUPPORT
template <typename TensorType>
struct get_eigen_plain_type<Eigen::TensorRef<TensorType> > {
typedef TensorType type;
};
#endif
#include "eigenpy/expose.hpp"
namespace internal {
template <class T1, class T2>
struct has_operator_equal_impl {
template <class U, class V>
static auto check(U *) -> decltype(std::declval<U>() == std::declval<V>());
template <typename, typename>
static auto check(...) -> std::false_type;
using type = typename std::is_same<bool, decltype(check<T1, T2>(0))>::type;
};
} // namespace internal
template <class T1, class T2 = T1>
struct has_operator_equal : internal::has_operator_equal_impl<T1, T2>::type {};
} // namespace eigenpy
#endif // ifndef __eigenpy_fwd_hpp__
#include "eigenpy/alignment.hpp"
#include "eigenpy/id.hpp"
#endif // ifndef __eigenpy_fwd_hpp__
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2019, INRIA
* Copyright 2018-2023, INRIA
*/
#ifndef __eigenpy_geometry_conversion_hpp__
#define __eigenpy_geometry_conversion_hpp__
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <boost/python.hpp>
namespace eigenpy
{
namespace bp = boost::python;
template<typename Scalar,int Options=0>
struct EulerAnglesConvertor
{
typedef typename Eigen::Matrix<Scalar,3,1,Options> Vector3;
typedef typename Eigen::Matrix<Scalar,3,3,Options> Matrix3;
typedef typename Vector3::Index Index;
typedef typename Eigen::AngleAxis<Scalar> AngleAxis;
static void expose()
{
bp::def("toEulerAngles",&EulerAnglesConvertor::toEulerAngles,
bp::args("mat (dim 3x3)","a0","a1","a2"),
"It returns the Euler-angles of the rotation matrix mat using the convention defined by the triplet (a0,a1,a2).");
bp::def("fromEulerAngles",&EulerAnglesConvertor::fromEulerAngles,
bp::args("ea (vector of Euler angles)","a0","a1","a2"),
"It returns the rotation matrix associated to the Euler angles using the convention defined by the triplet (a0,a1,a2).");
}
static Vector3 toEulerAngles(const Matrix3 & mat,
Index a0,
Index a1,
Index a2)
{
return mat.eulerAngles(a0,a1,a2);
}
static Matrix3 fromEulerAngles(const Vector3 & ea,
Index a0,
Index a1,
Index a2)
{
Matrix3 mat;
mat = AngleAxis(ea[0], Vector3::Unit(a0))
* AngleAxis(ea[1], Vector3::Unit(a1))
* AngleAxis(ea[2], Vector3::Unit(a2));
return mat;
}
};
} // namespace eigenpy
#endif // define __eigenpy_geometry_conversion_hpp__
#include "eigenpy/fwd.hpp"
namespace eigenpy {
template <typename Scalar, int Options = 0>
struct EulerAnglesConvertor {
typedef typename Eigen::Matrix<Scalar, 3, 1, Options> Vector3;
typedef typename Eigen::Matrix<Scalar, 3, 3, Options> Matrix3;
typedef typename Vector3::Index Index;
typedef typename Eigen::AngleAxis<Scalar> AngleAxis;
static void expose() {
bp::def("toEulerAngles", &EulerAnglesConvertor::toEulerAngles,
bp::args("rotation_matrix", "a0", "a1", "a2"),
"It returns the Euler-angles of the rotation matrix mat using the "
"convention defined by the triplet (a0,a1,a2).");
bp::def("fromEulerAngles", &EulerAnglesConvertor::fromEulerAngles,
bp::args("euler_angles", "a0", "a1", "a2"),
"It returns the rotation matrix associated to the Euler angles "
"using the convention defined by the triplet (a0,a1,a2).");
}
static Vector3 toEulerAngles(const Matrix3& mat, Index a0, Index a1,
Index a2) {
return mat.eulerAngles(a0, a1, a2);
}
static Matrix3 fromEulerAngles(const Vector3& ea, Index a0, Index a1,
Index a2) {
Matrix3 mat;
mat = AngleAxis(ea[0], Vector3::Unit(a0)) *
AngleAxis(ea[1], Vector3::Unit(a1)) *
AngleAxis(ea[2], Vector3::Unit(a2));
return mat;
}
};
} // namespace eigenpy
#endif // define __eigenpy_geometry_conversion_hpp__
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2019, INRIA
* Copyright 2018-2020, INRIA
*/
#ifndef __eigenpy_geometry_hpp__
#define __eigenpy_geometry_hpp__
#include "eigenpy/eigenpy_export.h"
#include "eigenpy/config.hpp"
namespace eigenpy
{
void EIGENPY_EXPORT exposeQuaternion();
void EIGENPY_EXPORT exposeAngleAxis();
void EIGENPY_EXPORT exposeGeometryConversion();
} // namespace eigenpy
namespace eigenpy {
#endif // define __eigenpy_geometry_hpp__
void EIGENPY_DLLAPI exposeQuaternion();
void EIGENPY_DLLAPI exposeAngleAxis();
void EIGENPY_DLLAPI exposeGeometryConversion();
} // namespace eigenpy
#endif // define __eigenpy_geometry_hpp__
//
// Copyright (c) 2024 INRIA
//
#ifndef __eigenpy_id_hpp__
#define __eigenpy_id_hpp__
#include <boost/python.hpp>
#include <boost/cstdint.hpp>
namespace eigenpy {
///
/// \brief Add the Python method id to retrieving a unique id for a given object
/// exposed with Boost.Python
///
template <class C>
struct IdVisitor : public bp::def_visitor<IdVisitor<C> > {
template <class PyClass>
void visit(PyClass& cl) const {
cl.def("id", &id, bp::arg("self"),
"Returns the unique identity of an object.\n"
"For object held in C++, it corresponds to its memory address.");
}
private:
static boost::int64_t id(const C& self) {
return boost::int64_t(reinterpret_cast<const void*>(&self));
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_id_hpp__
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2019, INRIA
/// Copyright (c) 2016-2024 CNRS INRIA
/// This file was originally taken from Pinocchio (header
/// <pinocchio/bindings/python/utils/std-vector.hpp>)
///
#ifndef __eigenpy_map_hpp__
#define __eigenpy_map_hpp__
#include "eigenpy/pickle-vector.hpp"
#include "eigenpy/registration.hpp"
#include "eigenpy/utils/empty-visitor.hpp"
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
#include <boost/python/stl_iterator.hpp>
#include <boost/python/to_python_converter.hpp>
namespace eigenpy {
/// \brief Change the behavior of indexing (method __getitem__ in Python).
/// This is suitable e.g. for container of Eigen matrix objects if you want to
/// mutate them.
/// \sa overload_base_get_item_for_std_vector
template <typename Container>
struct overload_base_get_item_for_map
: public boost::python::def_visitor<
overload_base_get_item_for_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");
boost::python::throw_error_already_set();
}
typename boost::python::to_python_indirect<
data_type&, boost::python::detail::make_reference_holder>
convert;
return boost::python::object(boost::python::handle<>(convert(i->second)));
}
static index_type convert_index(Container& /*container*/, PyObject* i_) {
boost::python::extract<key_type const&> i(i_);
if (i.check()) {
return i();
} else {
boost::python::extract<key_type> i(i_);
if (i.check()) return i();
}
PyErr_SetString(PyExc_TypeError, "Invalid index type");
boost::python::throw_error_already_set();
return index_type();
}
};
///////////////////////////////////////////////////////////////////////////////
// The following snippet of code has been taken from the header
// https://github.com/loco-3d/crocoddyl/blob/v2.1.0/bindings/python/crocoddyl/utils/map-converter.hpp
// The Crocoddyl library is written by Carlos Mastalli, Nicolas Mansard and
// Rohan Budhiraja.
///////////////////////////////////////////////////////////////////////////////
namespace bp = boost::python;
/**
* @brief Create a pickle interface for the map type
*
* @param[in] Container Map type to be pickled
* \sa Pickle
*/
template <typename Container>
struct PickleMap : public PickleVector<Container> {
static void setstate(bp::object op, bp::tuple tup) {
Container& o = bp::extract<Container&>(op)();
bp::stl_input_iterator<typename Container::value_type> begin(tup[0]), end;
o.insert(begin, end);
}
};
/// Conversion from dict to map solution proposed in
/// https://stackoverflow.com/questions/6116345/boostpython-possible-to-automatically-convert-from-dict-stdmap
/// This template encapsulates the conversion machinery.
template <typename Container>
struct dict_to_map {
static void register_converter() {
bp::converter::registry::push_back(&dict_to_map::convertible,
&dict_to_map::construct,
bp::type_id<Container>());
}
/// Check if conversion is possible
static void* convertible(PyObject* object) {
// Check if it is a list
if (!PyObject_GetIter(object)) return 0;
return object;
}
/// Perform the conversion
static void construct(PyObject* object,
bp::converter::rvalue_from_python_stage1_data* data) {
// convert the PyObject pointed to by `object` to a bp::dict
bp::handle<> handle(bp::borrowed(object)); // "smart ptr"
bp::dict dict(handle);
#include "eigenpy/fwd.hpp"
#include <numpy/arrayobject.h>
#include "eigenpy/exception.hpp"
#include "eigenpy/stride.hpp"
namespace eigenpy
{
template<typename MatType, typename InputScalar, int IsVector>
struct MapNumpyTraits {};
/* Wrap a numpy::array with an Eigen::Map. No memory copy. */
template<typename MatType, typename InputScalar>
struct MapNumpy
{
typedef MapNumpyTraits<MatType, InputScalar, MatType::IsVectorAtCompileTime> Impl;
typedef typename Impl::EigenMap EigenMap;
typedef typename Impl::Stride Stride;
static inline EigenMap map( PyArrayObject* pyArray );
};
} // namespace eigenpy
/* --- DETAILS ------------------------------------------------------------------ */
/* --- DETAILS ------------------------------------------------------------------ */
/* --- DETAILS ------------------------------------------------------------------ */
namespace eigenpy
{
template<typename MatType, typename InputScalar>
struct MapNumpyTraits<MatType,InputScalar,0>
{
typedef typename StrideType<MatType>::type Stride;
typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime> EquivalentInputMatrixType;
typedef Eigen::Map<EquivalentInputMatrixType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap;
static EigenMap mapImpl( PyArrayObject* pyArray )
{
assert( PyArray_NDIM(pyArray) == 2 );
assert( (PyArray_DIMS(pyArray)[0]<INT_MAX)
&& (PyArray_DIMS(pyArray)[1]<INT_MAX)
&& (PyArray_STRIDE(pyArray, 0)<INT_MAX)
&& (PyArray_STRIDE(pyArray, 1)<INT_MAX) );
const int R = (int)PyArray_DIMS(pyArray)[0];
const int C = (int)PyArray_DIMS(pyArray)[1];
const long int itemsize = PyArray_ITEMSIZE(pyArray);
const int stride1 = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
const int stride2 = (int)PyArray_STRIDE(pyArray, 1) / (int)itemsize;
Stride stride(stride2,stride1);
if( (MatType::RowsAtCompileTime!=R)
&& (MatType::RowsAtCompileTime!=Eigen::Dynamic) )
{ throw eigenpy::Exception("The number of rows does not fit with the matrix type."); }
if( (MatType::ColsAtCompileTime!=C)
&& (MatType::ColsAtCompileTime!=Eigen::Dynamic) )
{ throw eigenpy::Exception("The number of columns does not fit with the matrix type."); }
InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray));
return EigenMap( pyData, R,C, stride );
// get a pointer to memory into which we construct the map
// this is provided by the Python runtime
typedef bp::converter::rvalue_from_python_storage<Container> storage_type;
void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;
// placement-new allocate the result
new (storage) Container();
// iterate over the dictionary `dict`, fill up the map `map`
Container& map(*(static_cast<Container*>(storage)));
bp::list keys(dict.keys());
int keycount(static_cast<int>(bp::len(keys)));
for (int i = 0; i < keycount; ++i) {
// get the key
bp::object keyobj(keys[i]);
bp::extract<typename Container::key_type> keyproxy(keyobj);
if (!keyproxy.check()) {
PyErr_SetString(PyExc_KeyError, "Bad key type");
bp::throw_error_already_set();
}
typename Container::key_type key = keyproxy();
// get the corresponding value
bp::object valobj(dict[keyobj]);
bp::extract<typename Container::mapped_type> valproxy(valobj);
if (!valproxy.check()) {
PyErr_SetString(PyExc_ValueError, "Bad value type");
bp::throw_error_already_set();
}
typename Container::mapped_type val = valproxy();
map.emplace(key, val);
}
};
template<typename MatType, typename InputScalar>
struct MapNumpyTraits<MatType,InputScalar,1>
{
typedef typename StrideType<MatType>::type Stride;
typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime> EquivalentInputMatrixType;
typedef Eigen::Map<EquivalentInputMatrixType,EIGENPY_DEFAULT_ALIGNMENT_VALUE,Stride> EigenMap;
static EigenMap mapImpl( PyArrayObject* pyArray )
{
assert( PyArray_NDIM(pyArray) <= 2 );
int rowMajor;
if( PyArray_NDIM(pyArray)==1 ) rowMajor = 0;
else if (PyArray_DIMS(pyArray)[0] == 0) rowMajor = 0; // handle zero-size vector
else if (PyArray_DIMS(pyArray)[1] == 0) rowMajor = 1; // handle zero-size vector
else rowMajor = (PyArray_DIMS(pyArray)[0]>PyArray_DIMS(pyArray)[1])?0:1;
assert( (PyArray_DIMS(pyArray)[rowMajor]< INT_MAX)
&& (PyArray_STRIDE(pyArray, rowMajor) ));
const int R = (int)PyArray_DIMS(pyArray)[rowMajor];
const long int itemsize = PyArray_ITEMSIZE(pyArray);
const int stride = (int) PyArray_STRIDE(pyArray, rowMajor) / (int) itemsize;;
if( (MatType::MaxSizeAtCompileTime!=R)
&& (MatType::MaxSizeAtCompileTime!=Eigen::Dynamic) )
{ throw eigenpy::Exception("The number of elements does not fit with the vector type."); }
InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray));
return EigenMap( pyData, R, Stride(stride) );
// remember the location for later
data->convertible = storage;
}
static bp::dict todict(Container& self) {
bp::dict dict;
typename Container::const_iterator it;
for (it = self.begin(); it != self.end(); ++it) {
dict.setdefault(it->first, it->second);
}
};
return dict;
}
};
/// Policies which handle the non-default constructible case
/// and set_item() using emplace().
template <class Container, bool NoProxy>
struct emplace_set_derived_policies
: bp::map_indexing_suite<
Container, NoProxy,
emplace_set_derived_policies<Container, NoProxy> > {
typedef typename Container::key_type index_type;
typedef typename Container::value_type::second_type data_type;
typedef typename Container::value_type value_type;
using DerivedPolicies =
bp::detail::final_map_derived_policies<Container, NoProxy>;
template <class Class>
static void extension_def(Class& cl) {
// Wrap the map's element (value_type)
std::string elem_name = "map_indexing_suite_";
bp::object class_name(cl.attr("__name__"));
bp::extract<std::string> class_name_extractor(class_name);
elem_name += class_name_extractor();
elem_name += "_entry";
namespace mpl = boost::mpl;
typedef typename mpl::if_<
mpl::and_<boost::is_class<data_type>, mpl::bool_<!NoProxy> >,
bp::return_internal_reference<>, bp::default_call_policies>::type
get_data_return_policy;
bp::class_<value_type>(elem_name.c_str(), bp::no_init)
.def("__repr__", &DerivedPolicies::print_elem)
.def("data", &DerivedPolicies::get_data, get_data_return_policy())
.def("key", &DerivedPolicies::get_key);
}
template<typename MatType, typename InputScalar>
typename MapNumpy<MatType,InputScalar>::EigenMap MapNumpy<MatType,InputScalar>::map( PyArrayObject* pyArray )
{
return Impl::mapImpl(pyArray);
static void set_item(Container& container, index_type i, data_type const& v) {
container.emplace(i, v);
}
};
/**
* @brief Expose the map-like container, e.g. (std::map).
*
* @param[in] Container Container to expose.
* @param[in] NoProxy When set to false, the elements will be copied when
* returned to Python.
*/
template <class Container, bool NoProxy = false>
struct GenericMapVisitor
: public emplace_set_derived_policies<Container, NoProxy>,
public dict_to_map<Container> {
typedef dict_to_map<Container> FromPythonDictConverter;
template <typename DerivedVisitor>
static void expose(const std::string& class_name,
const std::string& doc_string,
const bp::def_visitor<DerivedVisitor>& visitor) {
namespace bp = bp;
if (!register_symbolic_link_to_registered_type<Container>()) {
bp::class_<Container>(class_name.c_str(), doc_string.c_str())
.def(GenericMapVisitor())
.def("todict", &FromPythonDictConverter::todict, bp::arg("self"),
"Returns the map type as a Python dictionary.")
.def_pickle(PickleMap<Container>())
.def(visitor);
// Register conversion
FromPythonDictConverter::register_converter();
}
}
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);
}
};
} // namespace eigenpy
} // namespace eigenpy
#endif // ifndef __eigenpy_map_hpp__
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2019, INRIA
* Copyright 2018-2023, INRIA
*/
#include "eigenpy/fwd.hpp"
EIGENPY_DEPRECATED_FILE(
"This header file is now useless and should not be included anymore.")
#ifndef __eigenpy_memory_hpp__
#define __eigenpy_memory_hpp__
#include <boost/python.hpp>
/**
* This section contains a convenience MACRO which allows an easy specialization of
* Boost Python Object allocator for struct data types containing Eigen objects and requiring
* strict alignment.
*
* This code was proposed as an stackoverflow answer:
* http://stackoverflow.com/questions/13177573/how-to-expose-aligned-class-with-boost-python/29694518
* Leading to this page proposing the solution:
* http://fhtagn.net/prog/2015/04/16/quaternion_boost_python.html
*
* This section contains a convenience MACRO which allows an easy specialization
* of Boost Python Object allocator for struct data types containing Eigen
* objects and requiring strict alignment.
*/
#define EIGENPY_DEFINE_STRUCT_ALLOCATOR_SPECIALIZATION(...) \
namespace boost { namespace python { namespace objects { \
template<> \
struct instance< value_holder<__VA_ARGS__> > \
{ \
typedef value_holder<__VA_ARGS__> Data; \
PyObject_VAR_HEAD \
PyObject* dict; \
PyObject* weakrefs; \
instance_holder* objects; \
\
typedef type_with_alignment< \
::boost::alignment_of<Data>::value \
>::type align_t; \
\
union \
{ \
align_t align; \
char bytes[sizeof(Data) + 16]; \
} storage; \
}; \
\
template<class Derived> \
struct make_instance_impl<__VA_ARGS__, value_holder<__VA_ARGS__>, Derived> \
{ \
typedef __VA_ARGS__ T; \
typedef value_holder<__VA_ARGS__> Holder; \
typedef objects::instance<Holder> instance_t; \
\
template <class Arg> \
static inline PyObject* execute(Arg & x) \
{ \
BOOST_MPL_ASSERT((mpl::or_<is_class<T>, is_union<T> >)); \
\
PyTypeObject* type = Derived::get_class_object(x); \
\
if (type == 0) \
return python::detail::none(); \
\
PyObject* raw_result = type->tp_alloc(type, objects::additional_instance_size<Holder>::value); \
if (raw_result != 0) \
{ \
python::detail::decref_guard protect(raw_result); \
instance_t* instance = (instance_t*)(void*)raw_result; \
Holder* holder = Derived::construct(&instance->storage, (PyObject*)instance, x); \
holder->install(raw_result); \
\
Py_ssize_t holder_offset = reinterpret_cast<Py_ssize_t>(holder) \
- reinterpret_cast<Py_ssize_t>(&instance->storage) \
+ static_cast<Py_ssize_t>(offsetof(instance_t, storage)); \
Py_SIZE(instance) = holder_offset; \
\
protect.cancel(); \
} \
return raw_result; \
} \
}; \
\
template<> \
struct make_instance<__VA_ARGS__, value_holder<__VA_ARGS__> > \
: make_instance_impl<__VA_ARGS__, value_holder<__VA_ARGS__>, make_instance<__VA_ARGS__,value_holder<__VA_ARGS__> > > \
{ \
template <class U> \
static inline PyTypeObject* get_class_object(U &) \
{ \
return converter::registered<__VA_ARGS__>::converters.get_class_object(); \
} \
\
static inline value_holder<__VA_ARGS__>* construct(void* storage, PyObject* instance, reference_wrapper<__VA_ARGS__ const> x) \
{ \
void* aligned_storage = reinterpret_cast<void*>((reinterpret_cast<size_t>(storage) & ~(size_t(15))) + 16); \
value_holder<__VA_ARGS__>* new_holder = new (aligned_storage) value_holder<__VA_ARGS__>(instance, x); \
return new_holder; \
} \
}; \
}}}
#define EIGENPY_DEFINE_STRUCT_ALLOCATOR_SPECIALIZATION(...) \
EIGENPY_DEPRECATED_MACRO(EIGENPY_DEFINE_STRUCT_ALLOCATOR_SPECIALIZATION(), \
"it is no more needed.")
#endif // __eigenpy_memory_hpp__
#endif // __eigenpy_memory_hpp__
/*
* Copyright 2020-2023 INRIA
*/
#ifndef __eigenpy_numpy_allocator_hpp__
#define __eigenpy_numpy_allocator_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/eigen-allocator.hpp"
#include "eigenpy/numpy-type.hpp"
#include "eigenpy/register.hpp"
namespace eigenpy {
template <typename EigenType, typename BaseType>
struct numpy_allocator_impl;
template <typename EigenType>
struct numpy_allocator_impl_matrix;
template <typename MatType>
struct numpy_allocator_impl<
MatType, Eigen::MatrixBase<typename remove_const_reference<MatType>::type> >
: numpy_allocator_impl_matrix<MatType> {};
template <typename MatType>
struct numpy_allocator_impl<
const MatType,
const Eigen::MatrixBase<typename remove_const_reference<MatType>::type> >
: numpy_allocator_impl_matrix<const MatType> {};
// template <typename MatType>
// struct numpy_allocator_impl<MatType &, Eigen::MatrixBase<MatType> > :
// numpy_allocator_impl_matrix<MatType &>
//{};
template <typename MatType>
struct numpy_allocator_impl<const MatType &, const Eigen::MatrixBase<MatType> >
: numpy_allocator_impl_matrix<const MatType &> {};
template <typename EigenType,
typename BaseType = typename get_eigen_base_type<EigenType>::type>
struct NumpyAllocator : numpy_allocator_impl<EigenType, BaseType> {};
template <typename MatType>
struct numpy_allocator_impl_matrix {
template <typename SimilarMatrixType>
static PyArrayObject *allocate(
const Eigen::MatrixBase<SimilarMatrixType> &mat, npy_intp nd,
npy_intp *shape) {
typedef typename SimilarMatrixType::Scalar Scalar;
const int code = Register::getTypeCode<Scalar>();
PyArrayObject *pyArray = (PyArrayObject *)call_PyArray_SimpleNew(
static_cast<int>(nd), shape, code);
// Copy data
EigenAllocator<SimilarMatrixType>::copy(mat, pyArray);
return pyArray;
}
};
#ifdef EIGENPY_WITH_TENSOR_SUPPORT
template <typename TensorType>
struct numpy_allocator_impl_tensor;
template <typename TensorType>
struct numpy_allocator_impl<TensorType, Eigen::TensorBase<TensorType> >
: numpy_allocator_impl_tensor<TensorType> {};
template <typename TensorType>
struct numpy_allocator_impl<const TensorType,
const Eigen::TensorBase<TensorType> >
: numpy_allocator_impl_tensor<const TensorType> {};
template <typename TensorType>
struct numpy_allocator_impl_tensor {
template <typename TensorDerived>
static PyArrayObject *allocate(const TensorDerived &tensor, npy_intp nd,
npy_intp *shape) {
const int code = Register::getTypeCode<typename TensorDerived::Scalar>();
PyArrayObject *pyArray = (PyArrayObject *)call_PyArray_SimpleNew(
static_cast<int>(nd), shape, code);
// Copy data
EigenAllocator<TensorDerived>::copy(
static_cast<const TensorDerived &>(tensor), pyArray);
return pyArray;
}
};
#endif
template <typename MatType>
struct numpy_allocator_impl_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 numpy_allocator_impl_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();
#if NPY_ABI_VERSION < 0x02000000
const int elsize = call_PyArray_DescrFromType(Scalar_type_code)->elsize;
#else
const int elsize =
PyDataType_ELSIZE(call_PyArray_DescrFromType(Scalar_type_code));
#endif
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 numpy_allocator_impl_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 numpy_allocator_impl_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();
#if NPY_ABI_VERSION < 0x02000000
const int elsize = call_PyArray_DescrFromType(Scalar_type_code)->elsize;
#else
const int elsize =
PyDataType_ELSIZE(call_PyArray_DescrFromType(Scalar_type_code));
#endif
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
#ifdef EIGENPY_WITH_TENSOR_SUPPORT
template <typename TensorType>
struct numpy_allocator_impl_tensor<Eigen::TensorRef<TensorType> > {
typedef Eigen::TensorRef<TensorType> RefType;
static PyArrayObject *allocate(RefType &tensor, npy_intp nd,
npy_intp *shape) {
typedef typename RefType::Scalar Scalar;
static const bool IsRowMajor = TensorType::Options & Eigen::RowMajorBit;
enum {
NPY_ARRAY_MEMORY_CONTIGUOUS =
IsRowMajor ? NPY_ARRAY_CARRAY : NPY_ARRAY_FARRAY
};
if (NumpyType::sharedMemory()) {
const int Scalar_type_code = Register::getTypeCode<Scalar>();
// static const Index NumIndices = TensorType::NumIndices;
// const int elsize =
// call_PyArray_DescrFromType(Scalar_type_code)->elsize; npy_intp
// strides[NumIndices];
PyArrayObject *pyArray = (PyArrayObject *)call_PyArray_New(
getPyArrayType(), static_cast<int>(nd), shape, Scalar_type_code, NULL,
const_cast<Scalar *>(tensor.data()),
NPY_ARRAY_MEMORY_CONTIGUOUS | NPY_ARRAY_ALIGNED);
return pyArray;
} else {
return NumpyAllocator<TensorType>::allocate(tensor, nd, shape);
}
}
};
template <typename TensorType>
struct numpy_allocator_impl_tensor<const Eigen::TensorRef<const TensorType> > {
typedef const Eigen::TensorRef<const TensorType> RefType;
static PyArrayObject *allocate(RefType &tensor, npy_intp nd,
npy_intp *shape) {
typedef typename RefType::Scalar Scalar;
static const bool IsRowMajor = TensorType::Options & Eigen::RowMajorBit;
enum {
NPY_ARRAY_MEMORY_CONTIGUOUS_RO =
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, NULL,
const_cast<Scalar *>(tensor.data()),
NPY_ARRAY_MEMORY_CONTIGUOUS_RO | NPY_ARRAY_ALIGNED);
return pyArray;
} else {
return NumpyAllocator<TensorType>::allocate(tensor, nd, shape);
}
}
};
#endif
} // namespace eigenpy
#endif // ifndef __eigenpy_numpy_allocator_hpp__
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2023, INRIA
*/
#ifndef __eigenpy_numpy_map_hpp__
#define __eigenpy_numpy_map_hpp__
#include "eigenpy/exception.hpp"
#include "eigenpy/fwd.hpp"
#include "eigenpy/stride.hpp"
namespace eigenpy {
template <typename MatType, typename InputScalar, int AlignmentValue,
typename Stride, bool IsVector = MatType::IsVectorAtCompileTime>
struct numpy_map_impl_matrix;
template <typename EigenType, typename InputScalar, int AlignmentValue,
typename Stride,
typename BaseType = typename get_eigen_base_type<EigenType>::type>
struct numpy_map_impl;
template <typename MatType, typename InputScalar, int AlignmentValue,
typename Stride>
struct numpy_map_impl<MatType, InputScalar, AlignmentValue, Stride,
Eigen::MatrixBase<MatType> >
: numpy_map_impl_matrix<MatType, InputScalar, AlignmentValue, Stride> {};
template <typename MatType, typename InputScalar, int AlignmentValue,
typename Stride>
struct numpy_map_impl<const MatType, InputScalar, AlignmentValue, Stride,
const Eigen::MatrixBase<MatType> >
: numpy_map_impl_matrix<const MatType, InputScalar, AlignmentValue,
Stride> {};
template <typename MatType, typename InputScalar, int AlignmentValue,
typename Stride>
struct numpy_map_impl_matrix<MatType, InputScalar, AlignmentValue, Stride,
false> {
typedef Eigen::Matrix<InputScalar, MatType::RowsAtCompileTime,
MatType::ColsAtCompileTime, MatType::Options>
EquivalentInputMatrixType;
typedef Eigen::Map<EquivalentInputMatrixType, AlignmentValue, Stride>
EigenMap;
static EigenMap map(PyArrayObject* pyArray, bool swap_dimensions = false) {
enum {
OuterStrideAtCompileTime = Stride::OuterStrideAtCompileTime,
InnerStrideAtCompileTime = Stride::InnerStrideAtCompileTime,
};
assert(PyArray_NDIM(pyArray) == 2 || PyArray_NDIM(pyArray) == 1);
const long int itemsize = PyArray_ITEMSIZE(pyArray);
int inner_stride = -1, outer_stride = -1;
int rows = -1, cols = -1;
if (PyArray_NDIM(pyArray) == 2) {
assert((PyArray_DIMS(pyArray)[0] < INT_MAX) &&
(PyArray_DIMS(pyArray)[1] < INT_MAX) &&
(PyArray_STRIDE(pyArray, 0) < INT_MAX) &&
(PyArray_STRIDE(pyArray, 1) < INT_MAX));
rows = (int)PyArray_DIMS(pyArray)[0];
cols = (int)PyArray_DIMS(pyArray)[1];
if (EquivalentInputMatrixType::IsRowMajor) {
inner_stride = (int)PyArray_STRIDE(pyArray, 1) / (int)itemsize;
outer_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
} else {
inner_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
outer_stride = (int)PyArray_STRIDE(pyArray, 1) / (int)itemsize;
}
} else if (PyArray_NDIM(pyArray) == 1) {
assert((PyArray_DIMS(pyArray)[0] < INT_MAX) &&
(PyArray_STRIDE(pyArray, 0) < INT_MAX));
if (!swap_dimensions) {
rows = (int)PyArray_DIMS(pyArray)[0];
cols = 1;
if (EquivalentInputMatrixType::IsRowMajor) {
outer_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
inner_stride = 0;
} else {
inner_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
outer_stride = 0;
}
} else {
rows = 1;
cols = (int)PyArray_DIMS(pyArray)[0];
if (EquivalentInputMatrixType::IsRowMajor) {
inner_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
outer_stride = 0;
} else {
inner_stride = 0;
outer_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
}
}
}
// Specific care for Eigen::Stride<-1,0>
if (InnerStrideAtCompileTime == 0 &&
OuterStrideAtCompileTime == Eigen::Dynamic) {
outer_stride = std::max(inner_stride, outer_stride);
inner_stride = 0;
}
Stride stride(
OuterStrideAtCompileTime == Eigen::Dynamic ? outer_stride
: OuterStrideAtCompileTime,
InnerStrideAtCompileTime == Eigen::Dynamic ? inner_stride
: InnerStrideAtCompileTime);
if ((MatType::RowsAtCompileTime != rows) &&
(MatType::RowsAtCompileTime != Eigen::Dynamic)) {
throw eigenpy::Exception(
"The number of rows does not fit with the matrix type.");
}
if ((MatType::ColsAtCompileTime != cols) &&
(MatType::ColsAtCompileTime != Eigen::Dynamic)) {
throw eigenpy::Exception(
"The number of columns does not fit with the matrix type.");
}
InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray));
return EigenMap(pyData, rows, cols, stride);
}
};
template <typename MatType, typename InputScalar, int AlignmentValue,
typename Stride>
struct numpy_map_impl_matrix<MatType, InputScalar, AlignmentValue, Stride,
true> {
typedef Eigen::Matrix<InputScalar, MatType::RowsAtCompileTime,
MatType::ColsAtCompileTime, MatType::Options>
EquivalentInputMatrixType;
typedef Eigen::Map<EquivalentInputMatrixType, AlignmentValue, Stride>
EigenMap;
static EigenMap map(PyArrayObject* pyArray, bool swap_dimensions = false) {
EIGENPY_UNUSED_VARIABLE(swap_dimensions);
assert(PyArray_NDIM(pyArray) <= 2);
int rowMajor;
if (PyArray_NDIM(pyArray) == 1)
rowMajor = 0;
else if (PyArray_DIMS(pyArray)[0] == 0)
rowMajor = 0; // handle zero-size vector
else if (PyArray_DIMS(pyArray)[1] == 0)
rowMajor = 1; // handle zero-size vector
else
rowMajor = (PyArray_DIMS(pyArray)[0] > PyArray_DIMS(pyArray)[1]) ? 0 : 1;
assert(PyArray_DIMS(pyArray)[rowMajor] < INT_MAX);
const int R = (int)PyArray_DIMS(pyArray)[rowMajor];
const long int itemsize = PyArray_ITEMSIZE(pyArray);
const int stride = (int)PyArray_STRIDE(pyArray, rowMajor) / (int)itemsize;
if ((MatType::MaxSizeAtCompileTime != R) &&
(MatType::MaxSizeAtCompileTime != Eigen::Dynamic)) {
throw eigenpy::Exception(
"The number of elements does not fit with the vector type.");
}
InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray));
assert(Stride(stride).inner() == stride &&
"Stride should be a dynamic stride");
return EigenMap(pyData, R, Stride(stride));
}
};
#ifdef EIGENPY_WITH_TENSOR_SUPPORT
template <typename TensorType, typename InputScalar, int AlignmentValue,
typename Stride>
struct numpy_map_impl_tensor;
template <typename TensorType, typename InputScalar, int AlignmentValue,
typename Stride>
struct numpy_map_impl<TensorType, InputScalar, AlignmentValue, Stride,
Eigen::TensorBase<TensorType> >
: numpy_map_impl_tensor<TensorType, InputScalar, AlignmentValue, Stride> {};
template <typename TensorType, typename InputScalar, int AlignmentValue,
typename Stride>
struct numpy_map_impl<const TensorType, InputScalar, AlignmentValue, Stride,
const Eigen::TensorBase<TensorType> >
: numpy_map_impl_tensor<const TensorType, InputScalar, AlignmentValue,
Stride> {};
template <typename TensorType, typename InputScalar, int AlignmentValue,
typename Stride>
struct numpy_map_impl_tensor {
typedef TensorType Tensor;
typedef typename Eigen::internal::traits<TensorType>::Index Index;
static const int Options = Eigen::internal::traits<TensorType>::Options;
static const int NumIndices = TensorType::NumIndices;
typedef Eigen::Tensor<InputScalar, NumIndices, Options, Index>
EquivalentInputTensorType;
typedef typename EquivalentInputTensorType::Dimensions Dimensions;
typedef Eigen::TensorMap<EquivalentInputTensorType, Options> EigenMap;
static EigenMap map(PyArrayObject* pyArray, bool swap_dimensions = false) {
EIGENPY_UNUSED_VARIABLE(swap_dimensions);
assert(PyArray_NDIM(pyArray) == NumIndices || NumIndices == Eigen::Dynamic);
Eigen::DSizes<Index, NumIndices> dimensions;
for (int k = 0; k < PyArray_NDIM(pyArray); ++k)
dimensions[k] = PyArray_DIMS(pyArray)[k];
InputScalar* pyData = reinterpret_cast<InputScalar*>(PyArray_DATA(pyArray));
return EigenMap(pyData, dimensions);
}
};
#endif
/* Wrap a numpy::array with an Eigen::Map. No memory copy. */
template <typename EigenType, typename InputScalar,
int AlignmentValue = EIGENPY_NO_ALIGNMENT_VALUE,
typename Stride = typename StrideType<EigenType>::type>
struct NumpyMap
: numpy_map_impl<EigenType, InputScalar, AlignmentValue, Stride> {};
} // namespace eigenpy
#endif // define __eigenpy_numpy_map_hpp__
/*
* Copyright 2018-2023 INRIA
*/
#ifndef __eigenpy_numpy_type_hpp__
#define __eigenpy_numpy_type_hpp__
#include <sstream>
#include <stdexcept>
#include <typeinfo>
#include "eigenpy/fwd.hpp"
#include "eigenpy/register.hpp"
#include "eigenpy/scalar-conversion.hpp"
namespace eigenpy {
template <typename Scalar>
bool np_type_is_convertible_into_scalar(const int np_type) {
const auto scalar_np_code =
static_cast<NPY_TYPES>(NumpyEquivalentType<Scalar>::type_code);
if (scalar_np_code >= NPY_USERDEF)
return np_type == Register::getTypeCode<Scalar>();
if (scalar_np_code == np_type) return true;
// Manage type promotion
switch (np_type) {
case NPY_BOOL:
return FromTypeToType<bool, Scalar>::value;
case NPY_INT8:
return FromTypeToType<int8_t, Scalar>::value;
case NPY_INT16:
return FromTypeToType<int16_t, Scalar>::value;
case NPY_INT32:
return FromTypeToType<int32_t, Scalar>::value;
case NPY_INT64:
return FromTypeToType<int64_t, Scalar>::value;
case NPY_UINT8:
return FromTypeToType<uint8_t, Scalar>::value;
case NPY_UINT16:
return FromTypeToType<uint16_t, Scalar>::value;
case NPY_UINT32:
return FromTypeToType<uint32_t, Scalar>::value;
case NPY_UINT64:
return FromTypeToType<uint64_t, Scalar>::value;
#if defined _WIN32 || defined __CYGWIN__
// Manage NPY_INT on Windows (NPY_INT32 is NPY_LONG).
// See https://github.com/stack-of-tasks/eigenpy/pull/455
case NPY_INT:
return FromTypeToType<int32_t, Scalar>::value;
case NPY_UINT:
return FromTypeToType<uint32_t, Scalar>::value;
#endif // WIN32
#if defined __APPLE__
// Manage NPY_LONGLONG on Mac (NPY_INT64 is NPY_LONG)..
// long long and long are both the same type
// but NPY_LONGLONG and NPY_LONG are different dtype.
// See https://github.com/stack-of-tasks/eigenpy/pull/455
case NPY_LONGLONG:
return FromTypeToType<int64_t, Scalar>::value;
case NPY_ULONGLONG:
return FromTypeToType<uint64_t, Scalar>::value;
#endif // MAC
case NPY_FLOAT:
return FromTypeToType<float, Scalar>::value;
case NPY_CFLOAT:
return FromTypeToType<std::complex<float>, Scalar>::value;
case NPY_DOUBLE:
return FromTypeToType<double, Scalar>::value;
case NPY_CDOUBLE:
return FromTypeToType<std::complex<double>, Scalar>::value;
case NPY_LONGDOUBLE:
return FromTypeToType<long double, Scalar>::value;
case NPY_CLONGDOUBLE:
return FromTypeToType<std::complex<long double>, Scalar>::value;
default:
return false;
}
}
struct EIGENPY_DLLAPI NumpyType {
static NumpyType& getInstance();
static bp::object make(PyArrayObject* pyArray, bool copy = false);
static bp::object make(PyObject* pyObj, bool copy = false);
static void sharedMemory(const bool value);
static bool sharedMemory();
static const PyTypeObject* getNumpyArrayType();
protected:
NumpyType();
bp::object pyModule;
// Numpy types
bp::object NumpyArrayObject;
PyTypeObject* NumpyArrayType;
bool shared_memory;
};
} // namespace eigenpy
#endif // ifndef __eigenpy_numpy_type_hpp__
/*
* Copyright 2020-2024 INRIA
*/
#ifndef __eigenpy_numpy_hpp__
#define __eigenpy_numpy_hpp__
#include "eigenpy/config.hpp"
#ifndef PY_ARRAY_UNIQUE_SYMBOL
#define PY_ARRAY_UNIQUE_SYMBOL EIGENPY_ARRAY_API
#endif
// For compatibility with Numpy 2.x. See:
// https://numpy.org/devdocs/reference/c-api/array.html#c.NPY_API_SYMBOL_ATTRIBUTE
#define NPY_API_SYMBOL_ATTRIBUTE EIGENPY_DLLAPI
// When building with MSVC, Python headers use some pragma operator to link
// against the Python DLL.
// Unfortunately, it can link against the wrong build type of the library
// leading to some linking issue.
// Boost::Python provides a helper specifically dedicated to selecting the right
// Python library depending on build type, so let's make use of it.
// Numpy headers drags Python with them. As a result, it
// is necessary to include this helper before including Numpy.
// See: https://github.com/stack-of-tasks/eigenpy/pull/514
#include <boost/python/detail/wrap_python.hpp>
#include <numpy/numpyconfig.h>
#ifdef NPY_1_8_API_VERSION
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#endif
// Allow compiling against NumPy 1.x and 2.x. See:
// https://github.com/numpy/numpy/blob/afea8fd66f6bdbde855f5aff0b4e73eb0213c646/doc/source/reference/c-api/array.rst#L1224
#if NPY_ABI_VERSION < 0x02000000
#define PyArray_DescrProto PyArray_Descr
#endif
#include <numpy/ndarrayobject.h>
#include <numpy/ufuncobject.h>
#if NPY_ABI_VERSION < 0x02000000
static inline PyArray_ArrFuncs* PyDataType_GetArrFuncs(PyArray_Descr* descr) {
return descr->f;
}
#endif
/* PEP 674 disallow using macros as l-values
see : https://peps.python.org/pep-0674/
*/
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE)
static inline void _Py_SET_TYPE(PyObject* o, PyTypeObject* type) {
Py_TYPE(o) = type;
}
#define Py_SET_TYPE(o, type) _Py_SET_TYPE((PyObject*)(o), type)
#endif
#if defined _WIN32 || defined __CYGWIN__
#define EIGENPY_GET_PY_ARRAY_TYPE(array) \
call_PyArray_MinScalarType(array)->type_num
#else
#define EIGENPY_GET_PY_ARRAY_TYPE(array) PyArray_MinScalarType(array)->type_num
#endif
#include <complex>
namespace eigenpy {
void EIGENPY_DLLAPI import_numpy();
int EIGENPY_DLLAPI PyArray_TypeNum(PyTypeObject* type);
// By default, the Scalar is considered as a Python object
template <typename Scalar, typename Enable = void>
struct NumpyEquivalentType {
enum { type_code = NPY_USERDEF };
};
template <>
struct NumpyEquivalentType<bool> {
enum { type_code = NPY_BOOL };
};
template <>
struct NumpyEquivalentType<char> {
enum { type_code = NPY_INT8 };
};
template <>
struct NumpyEquivalentType<unsigned char> {
enum { type_code = NPY_UINT8 };
};
template <>
struct NumpyEquivalentType<int8_t> {
enum { type_code = NPY_INT8 };
};
template <>
struct NumpyEquivalentType<int16_t> {
enum { type_code = NPY_INT16 };
};
template <>
struct NumpyEquivalentType<uint16_t> {
enum { type_code = NPY_UINT16 };
};
template <>
struct NumpyEquivalentType<int32_t> {
enum { type_code = NPY_INT32 };
};
template <>
struct NumpyEquivalentType<uint32_t> {
enum { type_code = NPY_UINT32 };
};
// On Windows, long is a 32 bytes type but it's a different type than int
// See https://github.com/stack-of-tasks/eigenpy/pull/455
#if defined _WIN32 || defined __CYGWIN__
template <>
struct NumpyEquivalentType<long> {
enum { type_code = NPY_INT32 };
};
template <>
struct NumpyEquivalentType<unsigned long> {
enum { type_code = NPY_UINT32 };
};
#endif // WIN32
template <>
struct NumpyEquivalentType<int64_t> {
enum { type_code = NPY_INT64 };
};
template <>
struct NumpyEquivalentType<uint64_t> {
enum { type_code = NPY_UINT64 };
};
// On Mac, long is a 64 bytes type but it's a different type than int64_t
// See https://github.com/stack-of-tasks/eigenpy/pull/455
#if defined __APPLE__
template <>
struct NumpyEquivalentType<long> {
enum { type_code = NPY_INT64 };
};
template <>
struct NumpyEquivalentType<unsigned long> {
enum { type_code = NPY_UINT64 };
};
#endif // MAC
// On Linux, long long is a 64 bytes type but it's a different type than int64_t
// See https://github.com/stack-of-tasks/eigenpy/pull/455
#if defined __linux__
#include <type_traits>
template <typename Scalar>
struct NumpyEquivalentType<
Scalar,
typename std::enable_if<!std::is_same<int64_t, long long>::value &&
std::is_same<Scalar, long long>::value>::type> {
enum { type_code = NPY_LONGLONG };
};
template <typename Scalar>
struct NumpyEquivalentType<
Scalar, typename std::enable_if<
!std::is_same<uint64_t, unsigned long long>::value &&
std::is_same<Scalar, unsigned long long>::value>::type> {
enum { type_code = NPY_ULONGLONG };
};
#endif // Linux
template <>
struct NumpyEquivalentType<float> {
enum { type_code = NPY_FLOAT };
};
template <>
struct NumpyEquivalentType<double> {
enum { type_code = NPY_DOUBLE };
};
template <>
struct NumpyEquivalentType<long double> {
enum { type_code = NPY_LONGDOUBLE };
};
template <>
struct NumpyEquivalentType<std::complex<float> > {
enum { type_code = NPY_CFLOAT };
};
template <>
struct NumpyEquivalentType<std::complex<double> > {
enum { type_code = NPY_CDOUBLE };
};
template <>
struct NumpyEquivalentType<std::complex<long double> > {
enum { type_code = NPY_CLONGDOUBLE };
};
template <typename Scalar>
bool isNumpyNativeType() {
if ((int)NumpyEquivalentType<Scalar>::type_code == NPY_USERDEF) return false;
return true;
}
} // namespace eigenpy
namespace eigenpy {
#if defined _WIN32 || defined __CYGWIN__
EIGENPY_DLLAPI bool call_PyArray_Check(PyObject*);
EIGENPY_DLLAPI PyObject* call_PyArray_SimpleNew(int nd, npy_intp* shape,
int np_type);
EIGENPY_DLLAPI PyObject* call_PyArray_New(PyTypeObject* py_type_ptr, int nd,
npy_intp* shape, int np_type,
void* data_ptr, int options);
EIGENPY_DLLAPI PyObject* call_PyArray_New(PyTypeObject* py_type_ptr, int nd,
npy_intp* shape, int np_type,
npy_intp* strides, void* data_ptr,
int options);
EIGENPY_DLLAPI int call_PyArray_ObjectType(PyObject*, int);
EIGENPY_DLLAPI PyTypeObject* getPyArrayType();
EIGENPY_DLLAPI PyArray_Descr* call_PyArray_DescrFromType(int typenum);
EIGENPY_DLLAPI void call_PyArray_InitArrFuncs(PyArray_ArrFuncs* funcs);
EIGENPY_DLLAPI int call_PyArray_RegisterDataType(PyArray_DescrProto* dtype);
EIGENPY_DLLAPI int call_PyArray_RegisterCanCast(PyArray_Descr* descr,
int totype,
NPY_SCALARKIND scalar);
EIGENPY_DLLAPI PyArray_Descr* call_PyArray_MinScalarType(PyArrayObject* arr);
EIGENPY_DLLAPI int call_PyArray_RegisterCastFunc(
PyArray_Descr* descr, int totype, PyArray_VectorUnaryFunc* castfunc);
#else
inline bool call_PyArray_Check(PyObject* py_obj) {
return PyArray_Check(py_obj);
}
inline PyObject* call_PyArray_SimpleNew(int nd, npy_intp* shape, int np_type) {
return PyArray_SimpleNew(nd, shape, np_type);
}
inline PyObject* call_PyArray_New(PyTypeObject* py_type_ptr, int nd,
npy_intp* shape, int np_type, void* data_ptr,
int options) {
return PyArray_New(py_type_ptr, nd, shape, np_type, NULL, data_ptr, 0,
options, NULL);
}
inline PyObject* call_PyArray_New(PyTypeObject* py_type_ptr, int nd,
npy_intp* shape, int np_type,
npy_intp* strides, void* data_ptr,
int options) {
return PyArray_New(py_type_ptr, nd, shape, np_type, strides, data_ptr, 0,
options, NULL);
}
inline int call_PyArray_ObjectType(PyObject* obj, int val) {
return PyArray_ObjectType(obj, val);
}
inline PyTypeObject* getPyArrayType() { return &PyArray_Type; }
inline PyArray_Descr* call_PyArray_DescrFromType(int typenum) {
return PyArray_DescrFromType(typenum);
}
inline void call_PyArray_InitArrFuncs(PyArray_ArrFuncs* funcs) {
PyArray_InitArrFuncs(funcs);
}
inline int call_PyArray_RegisterDataType(PyArray_DescrProto* dtype) {
return PyArray_RegisterDataType(dtype);
}
inline PyArray_Descr* call_PyArray_MinScalarType(PyArrayObject* arr) {
return PyArray_MinScalarType(arr);
}
inline int call_PyArray_RegisterCanCast(PyArray_Descr* descr, int totype,
NPY_SCALARKIND scalar) {
return PyArray_RegisterCanCast(descr, totype, scalar);
}
inline int call_PyArray_RegisterCastFunc(PyArray_Descr* descr, int totype,
PyArray_VectorUnaryFunc* castfunc) {
return PyArray_RegisterCastFunc(descr, totype, castfunc);
}
#endif
} // namespace eigenpy
#endif // ifndef __eigenpy_numpy_hpp__
///
/// Copyright (c) 2023 CNRS INRIA
///
/// Definitions for exposing boost::optional<T> types.
/// Also works with std::optional.
#ifndef __eigenpy_optional_hpp__
#define __eigenpy_optional_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/eigen-from-python.hpp"
#include "eigenpy/registration.hpp"
#include <boost/optional.hpp>
#ifdef EIGENPY_WITH_CXX17_SUPPORT
#include <optional>
#endif
#ifndef EIGENPY_DEFAULT_OPTIONAL
#define EIGENPY_DEFAULT_OPTIONAL boost::optional
#endif
namespace boost {
namespace python {
namespace converter {
template <typename T>
struct expected_pytype_for_arg<boost::optional<T> >
: expected_pytype_for_arg<T> {};
#ifdef EIGENPY_WITH_CXX17_SUPPORT
template <typename T>
struct expected_pytype_for_arg<std::optional<T> > : expected_pytype_for_arg<T> {
};
#endif
} // namespace converter
} // namespace python
} // namespace boost
namespace eigenpy {
namespace detail {
/// Helper struct to decide which type is the "none" type for a specific
/// optional<T> implementation.
template <template <typename> class OptionalTpl>
struct nullopt_helper {};
template <>
struct nullopt_helper<boost::optional> {
typedef boost::none_t type;
static type value() { return boost::none; }
};
#ifdef EIGENPY_WITH_CXX17_SUPPORT
template <>
struct nullopt_helper<std::optional> {
typedef std::nullopt_t type;
static type value() { return std::nullopt; }
};
#endif
template <typename NoneType>
struct NoneToPython {
static PyObject *convert(const NoneType &) { Py_RETURN_NONE; }
static void registration() {
if (!check_registration<NoneType>()) {
bp::to_python_converter<NoneType, NoneToPython, false>();
}
}
};
template <typename T,
template <typename> class OptionalTpl = EIGENPY_DEFAULT_OPTIONAL>
struct OptionalToPython {
static PyObject *convert(const OptionalTpl<T> &obj) {
if (obj)
return bp::incref(bp::object(*obj).ptr());
else {
return bp::incref(bp::object().ptr()); // None
}
}
static PyTypeObject const *get_pytype() {
return bp::converter::registered_pytype<T>::get_pytype();
}
static void registration() {
if (!check_registration<OptionalTpl<T> >()) {
bp::to_python_converter<OptionalTpl<T>, OptionalToPython, true>();
}
}
};
template <typename T,
template <typename> class OptionalTpl = EIGENPY_DEFAULT_OPTIONAL>
struct OptionalFromPython {
static void *convertible(PyObject *obj_ptr);
static void construct(PyObject *obj_ptr,
bp::converter::rvalue_from_python_stage1_data *memory);
static void registration();
};
template <typename T, template <typename> class OptionalTpl>
void *OptionalFromPython<T, OptionalTpl>::convertible(PyObject *obj_ptr) {
if (obj_ptr == Py_None) {
return obj_ptr;
}
bp::extract<T> bp_obj(obj_ptr);
if (!bp_obj.check())
return 0;
else
return obj_ptr;
}
template <typename T, template <typename> class OptionalTpl>
void OptionalFromPython<T, OptionalTpl>::construct(
PyObject *obj_ptr, bp::converter::rvalue_from_python_stage1_data *memory) {
// create storage
using rvalue_storage_t =
bp::converter::rvalue_from_python_storage<OptionalTpl<T> >;
void *storage =
reinterpret_cast<rvalue_storage_t *>(reinterpret_cast<void *>(memory))
->storage.bytes;
if (obj_ptr == Py_None) {
new (storage) OptionalTpl<T>(nullopt_helper<OptionalTpl>::value());
} else {
const T value = bp::extract<T>(obj_ptr);
new (storage) OptionalTpl<T>(value);
}
memory->convertible = storage;
}
template <typename T, template <typename> class OptionalTpl>
void OptionalFromPython<T, OptionalTpl>::registration() {
bp::converter::registry::push_back(
&convertible, &construct, bp::type_id<OptionalTpl<T> >(),
bp::converter::expected_pytype_for_arg<OptionalTpl<T> >::get_pytype);
}
} // namespace detail
/// Register converters for the type `optional<T>` to Python.
/// By default \tparam optional is `EIGENPY_DEFAULT_OPTIONAL`.
template <typename T,
template <typename> class OptionalTpl = EIGENPY_DEFAULT_OPTIONAL>
struct OptionalConverter {
static void registration() {
detail::OptionalToPython<T, OptionalTpl>::registration();
detail::OptionalFromPython<T, OptionalTpl>::registration();
}
};
} // namespace eigenpy
#endif // __eigenpy_optional_hpp__
//
// Copyright (c) 2019-2020 CNRS INRIA
//
#ifndef __eigenpy_utils_pickle_vector_hpp__
#define __eigenpy_utils_pickle_vector_hpp__
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
#include <boost/python/tuple.hpp>
namespace eigenpy {
///
/// \brief Create a pickle interface for the std::vector
///
/// \tparam VecType Vector Type to pickle
///
template <typename VecType>
struct PickleVector : boost::python::pickle_suite {
static boost::python::tuple getinitargs(const VecType&) {
return boost::python::make_tuple();
}
static boost::python::tuple getstate(boost::python::object op) {
return boost::python::make_tuple(
boost::python::list(boost::python::extract<const VecType&>(op)()));
}
static void setstate(boost::python::object op, boost::python::tuple tup) {
if (boost::python::len(tup) > 0) {
VecType& o = boost::python::extract<VecType&>(op)();
boost::python::stl_input_iterator<typename VecType::value_type> begin(
tup[0]),
end;
while (begin != end) {
o.push_back(*begin);
++begin;
}
}
}
static bool getstate_manages_dict() { return true; }
};
} // namespace eigenpy
#endif // ifndef __eigenpy_utils_pickle_vector_hpp__
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2019, INRIA
* Copyright 2014-2023 CNRS INRIA
*/
#ifndef __eigenpy_quaternion_hpp__
#define __eigenpy_quaternion_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/eigenpy.hpp"
#include "eigenpy/exception.hpp"
#include "eigenpy/eigen-from-python.hpp"
#include <Eigen/Core>
#include <Eigen/Geometry>
namespace boost {
namespace python {
namespace converter {
#include "eigenpy/exception.hpp"
#include "eigenpy/registration.hpp"
namespace eigenpy
{
class ExceptionIndex : public Exception
{
public:
ExceptionIndex(int index,int imin,int imax) : Exception("")
{
std::ostringstream oss; oss << "Index " << index << " out of range " << imin << ".."<< imax <<".";
message = oss.str();
}
};
namespace bp = boost::python;
template<typename QuaternionDerived> class QuaternionVisitor;
namespace internal
{
template<typename Scalar, int Options>
struct call_expose< Eigen::Quaternion<Scalar,Options> >
{
typedef Eigen::Quaternion<Scalar,Options> type;
static inline void run()
{
QuaternionVisitor<type>::expose();
}
};
} // namespace internal
template<typename Quaternion>
class QuaternionVisitor
: public bp::def_visitor< QuaternionVisitor<Quaternion> >
{
typedef Eigen::QuaternionBase<Quaternion> QuaternionBase;
typedef typename QuaternionBase::Scalar Scalar;
typedef typename Quaternion::Coefficients Coefficients;
typedef typename QuaternionBase::Vector3 Vector3;
typedef typename Eigen::Matrix<Scalar,4,1> Vector4;
typedef typename QuaternionBase::Matrix3 Matrix3;
typedef typename QuaternionBase::AngleAxisType AngleAxis;
public:
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def(bp::init<>("Default constructor"))
.def(bp::init<Matrix3>((bp::arg("matrixRotation")),"Initialize from rotation matrix."))
.def(bp::init<AngleAxis>((bp::arg("angleaxis")),"Initialize from angle axis."))
.def(bp::init<Quaternion>((bp::arg("clone")),"Copy constructor."))
.def("__init__",bp::make_constructor(&QuaternionVisitor::FromTwoVectors,
bp::default_call_policies(),
(bp::arg("u"),bp::arg("v"))),"Initialize from two vector u,v")
.def(bp::init<Scalar,Scalar,Scalar,Scalar>
((bp::arg("w"),bp::arg("x"),bp::arg("y"),bp::arg("z")),
"Initialize from coefficients.\n\n"
"... note:: The order of coefficients is *w*, *x*, *y*, *z*. "
"The [] operator numbers them differently, 0...4 for *x* *y* *z* *w*!"))
.add_property("x",
&QuaternionVisitor::getCoeff<0>,
&QuaternionVisitor::setCoeff<0>,"The x coefficient.")
.add_property("y",
&QuaternionVisitor::getCoeff<1>,
&QuaternionVisitor::setCoeff<1>,"The y coefficient.")
.add_property("z",
&QuaternionVisitor::getCoeff<2>,
&QuaternionVisitor::setCoeff<2>,"The z coefficient.")
.add_property("w",
&QuaternionVisitor::getCoeff<3>,
&QuaternionVisitor::setCoeff<3>,"The w coefficient.")
// .def("isApprox",(bool (Quaternion::*)(const Quaternion &))&Quaternion::template isApprox<Quaternion>,
// "Returns true if *this is approximately equal to other.")
// .def("isApprox",(bool (Quaternion::*)(const Quaternion &, const Scalar prec))&Quaternion::template isApprox<Quaternion>,
// "Returns true if *this is approximately equal to other, within the precision determined by prec..")
.def("isApprox",(bool (*)(const Quaternion &))&isApprox,
"Returns true if *this is approximately equal to other.")
.def("isApprox",(bool (*)(const Quaternion &, const Scalar prec))&isApprox,
"Returns true if *this is approximately equal to other, within the precision determined by prec..")
/* --- Methods --- */
.def("coeffs",(const Vector4 & (Quaternion::*)()const)&Quaternion::coeffs,
bp::return_value_policy<bp::copy_const_reference>())
.def("matrix",&Quaternion::matrix,"Returns an equivalent 3x3 rotation matrix. Similar to toRotationMatrix.")
.def("toRotationMatrix",&Quaternion::toRotationMatrix,"Returns an equivalent 3x3 rotation matrix.")
.def("setFromTwoVectors",&setFromTwoVectors,((bp::arg("a"),bp::arg("b"))),"Set *this to be the quaternion which transform a into b through a rotation."
,bp::return_self<>())
.def("conjugate",&Quaternion::conjugate,"Returns the conjugated quaternion. The conjugate of a quaternion represents the opposite rotation.")
.def("inverse",&Quaternion::inverse,"Returns the quaternion describing the inverse rotation.")
.def("setIdentity",&Quaternion::setIdentity,bp::return_self<>(),"Set *this to the idendity rotation.")
.def("norm",&Quaternion::norm,"Returns the norm of the quaternion's coefficients.")
.def("normalize",&Quaternion::normalize,"Normalizes the quaternion *this.")
.def("normalized",&Quaternion::normalized,"Returns a normalized copy of *this.")
.def("squaredNorm",&Quaternion::squaredNorm,"Returns the squared norm of the quaternion's coefficients.")
.def("dot",&Quaternion::template dot<Quaternion>,bp::arg("other"),"Returns the dot product of *this with other"
"Geometrically speaking, the dot product of two unit quaternions corresponds to the cosine of half the angle between the two rotations.")
.def("_transformVector",&Quaternion::_transformVector,bp::arg("vector"),"Rotation of a vector by a quaternion.")
.def("vec",&vec,"Returns a vector expression of the imaginary part (x,y,z).")
.def("angularDistance",&Quaternion::template angularDistance<Quaternion>,"Returns the angle (in radian) between two rotations.")
.def("slerp",&slerp,bp::args("t","other"),
"Returns the spherical linear interpolation between the two quaternions *this and other at the parameter t in [0;1].")
/* --- Operators --- */
.def(bp::self * bp::self)
.def(bp::self *= bp::self)
.def(bp::self * bp::other<Vector3>())
.def("__eq__",&QuaternionVisitor::__eq__)
.def("__ne__",&QuaternionVisitor::__ne__)
.def("__abs__",&Quaternion::norm)
.def("__len__",&QuaternionVisitor::__len__).staticmethod("__len__")
.def("__setitem__",&QuaternionVisitor::__setitem__)
.def("__getitem__",&QuaternionVisitor::__getitem__)
.def("assign",&assign<Quaternion>,
bp::arg("quat"),"Set *this from an quaternion quat and returns a reference to *this.",bp::return_self<>())
.def("assign",(Quaternion & (Quaternion::*)(const AngleAxis &))&Quaternion::operator=,
bp::arg("aa"),"Set *this from an angle-axis aa and returns a reference to *this.",bp::return_self<>())
.def("__str__",&print)
.def("__repr__",&print)
// .def("FromTwoVectors",&Quaternion::template FromTwoVectors<Vector3,Vector3>,
// bp::args("a","b"),
// "Returns the quaternion which transform a into b through a rotation.")
.def("FromTwoVectors",&FromTwoVectors,
bp::args("a","b"),
"Returns the quaternion which transform a into b through a rotation.",
bp::return_value_policy<bp::manage_new_object>())
.staticmethod("FromTwoVectors")
.def("Identity",&Quaternion::Identity,"Returns a quaternion representing an identity rotation.")
.staticmethod("Identity")
;
}
private:
template<int i>
static void setCoeff(Quaternion & self, Scalar value) { self.coeffs()[i] = value; }
template<int i>
static Scalar getCoeff(Quaternion & self) { return self.coeffs()[i]; }
static Quaternion & setFromTwoVectors(Quaternion & self, const Vector3 & a, const Vector3 & b)
{ return self.setFromTwoVectors(a,b); }
template<typename OtherQuat>
static Quaternion & assign(Quaternion & self, const OtherQuat & quat)
{ return self = quat; }
static Quaternion* FromTwoVectors(const Vector3& u, const Vector3& v)
{
Quaternion* q(new Quaternion); q->setFromTwoVectors(u,v);
return q;
}
static bool isApprox(const Quaternion & self, const Quaternion & other,
const Scalar prec = Eigen::NumTraits<Scalar>::dummy_precision)
{
return self.isApprox(other,prec);
}
static bool __eq__(const Quaternion& u, const Quaternion& v)
{
return u.isApprox(v,1e-9);
}
static bool __ne__(const Quaternion& u, const Quaternion& v)
{
return !__eq__(u,v);
}
static Scalar __getitem__(const Quaternion & self, int idx)
{
if((idx<0) || (idx>=4)) throw eigenpy::ExceptionIndex(idx,0,3);
return self.coeffs()[idx];
}
static void __setitem__(Quaternion& self, int idx, const Scalar value)
{
if((idx<0) || (idx>=4)) throw eigenpy::ExceptionIndex(idx,0,3);
self.coeffs()[idx] = value;
}
static int __len__() { return 4; }
static Vector3 vec(const Quaternion & self) { return self.vec(); }
static std::string print(const Quaternion & self)
{
std::stringstream ss;
ss << "(x,y,z,w) = " << self.coeffs().transpose() << std::endl;
return ss.str();
}
static Quaternion slerp(const Quaternion & self, const Scalar t, const Quaternion & other)
{ return self.slerp(t,other); }
public:
static void expose()
{
bp::class_<Quaternion>("Quaternion",
"Quaternion representing rotation.\n\n"
"Supported operations "
"('q is a Quaternion, 'v' is a Vector3): "
"'q*q' (rotation composition), "
"'q*=q', "
"'q*v' (rotating 'v' by 'q'), "
"'q==q', 'q!=q', 'q[0..3]'.",
bp::no_init)
.def(QuaternionVisitor<Quaternion>())
;
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_quaternion_hpp__
/// \brief Template specialization of rvalue_from_python_data
template <typename Quaternion>
struct rvalue_from_python_data<Eigen::QuaternionBase<Quaternion> const&>
: ::eigenpy::rvalue_from_python_data<Quaternion const&> {
EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(Quaternion const&)
};
template <class Quaternion>
struct implicit<Quaternion, Eigen::QuaternionBase<Quaternion> > {
typedef Quaternion Source;
typedef Eigen::QuaternionBase<Quaternion> Target;
static void* convertible(PyObject* obj) {
// Find a converter which can produce a Source instance from
// obj. The user has told us that Source can be converted to
// Target, and instantiating construct() below, ensures that
// at compile-time.
return implicit_rvalue_convertible_from_python(
obj, registered<Source>::converters)
? obj
: 0;
}
static void construct(PyObject* obj, rvalue_from_python_stage1_data* data) {
void* storage = ((rvalue_from_python_storage<Target>*)data)->storage.bytes;
arg_from_python<Source> get_source(obj);
bool convertible = get_source.convertible();
BOOST_VERIFY(convertible);
new (storage) Source(get_source());
// record successful construction
data->convertible = storage;
}
};
} // namespace converter
} // namespace python
} // namespace boost
namespace eigenpy {
class ExceptionIndex : public Exception {
public:
ExceptionIndex(int index, int imin, int imax) : Exception("") {
std::ostringstream oss;
oss << "Index " << index << " out of range " << imin << ".." << imax << ".";
message = oss.str();
}
};
template <typename QuaternionDerived>
class QuaternionVisitor;
template <typename Scalar, int Options>
struct call<Eigen::Quaternion<Scalar, Options> > {
typedef Eigen::Quaternion<Scalar, Options> Quaternion;
static inline void expose() { QuaternionVisitor<Quaternion>::expose(); }
static inline bool isApprox(
const Quaternion& self, const Quaternion& other,
const Scalar& prec = Eigen::NumTraits<Scalar>::dummy_precision()) {
return self.isApprox(other, prec);
}
};
template <typename Quaternion>
class QuaternionVisitor
: public bp::def_visitor<QuaternionVisitor<Quaternion> > {
typedef Eigen::QuaternionBase<Quaternion> QuaternionBase;
typedef typename QuaternionBase::Scalar Scalar;
typedef typename Quaternion::Coefficients Coefficients;
typedef typename QuaternionBase::Vector3 Vector3;
typedef Coefficients Vector4;
typedef typename QuaternionBase::Matrix3 Matrix3;
typedef typename QuaternionBase::AngleAxisType AngleAxis;
BOOST_PYTHON_FUNCTION_OVERLOADS(isApproxQuaternion_overload,
call<Quaternion>::isApprox, 2, 3)
public:
template <class PyClass>
void visit(PyClass& cl) const {
cl.def("__init__",
bp::make_constructor(&QuaternionVisitor::FromRotationMatrix,
bp::default_call_policies(), (bp::arg("R"))),
"Initialize from rotation matrix.\n"
"\tR : a rotation matrix 3x3.")
.def("__init__",
bp::make_constructor(&QuaternionVisitor::FromAngleAxis,
bp::default_call_policies(), (bp::arg("aa"))),
"Initialize from an angle axis.\n"
"\taa: angle axis object.")
.def("__init__",
bp::make_constructor(&QuaternionVisitor::FromOtherQuaternion,
bp::default_call_policies(),
(bp::arg("quat"))),
"Copy constructor.\n"
"\tquat: a quaternion.")
.def("__init__",
bp::make_constructor(&QuaternionVisitor::FromTwoVectors,
bp::default_call_policies(),
(bp::arg("u"), bp::arg("v"))),
"Initialize from two vectors u and v")
.def("__init__",
bp::make_constructor(&QuaternionVisitor::FromOneVector,
bp::default_call_policies(),
(bp::arg("vec4"))),
"Initialize from a vector 4D.\n"
"\tvec4 : a 4D vector representing quaternion coefficients in the "
"order xyzw.")
.def("__init__",
bp::make_constructor(&QuaternionVisitor::DefaultConstructor),
"Default constructor")
.def("__init__",
bp::make_constructor(
&QuaternionVisitor::FromCoefficients,
bp::default_call_policies(),
(bp::arg("w"), bp::arg("x"), bp::arg("y"), bp::arg("z"))),
"Initialize from coefficients.\n\n"
"... note:: The order of coefficients is *w*, *x*, *y*, *z*. "
"The [] operator numbers them differently, 0...4 for *x* *y* *z* "
"*w*!")
.add_property("x", &QuaternionVisitor::getCoeff<0>,
&QuaternionVisitor::setCoeff<0>, "The x coefficient.")
.add_property("y", &QuaternionVisitor::getCoeff<1>,
&QuaternionVisitor::setCoeff<1>, "The y coefficient.")
.add_property("z", &QuaternionVisitor::getCoeff<2>,
&QuaternionVisitor::setCoeff<2>, "The z coefficient.")
.add_property("w", &QuaternionVisitor::getCoeff<3>,
&QuaternionVisitor::setCoeff<3>, "The w coefficient.")
.def("isApprox", &call<Quaternion>::isApprox,
isApproxQuaternion_overload(
bp::args("self", "other", "prec"),
"Returns true if *this is approximately equal to other, "
"within the precision determined by prec."))
/* --- Methods --- */
.def("coeffs",
(const Vector4& (Quaternion::*)() const) & Quaternion::coeffs,
bp::arg("self"), "Returns a vector of the coefficients (x,y,z,w)",
bp::return_internal_reference<>())
.def("matrix", &Quaternion::matrix, bp::arg("self"),
"Returns an equivalent 3x3 rotation matrix. Similar to "
"toRotationMatrix.")
.def("toRotationMatrix", &Quaternion::toRotationMatrix,
// bp::arg("self"), // Bug in Boost.Python
"Returns an equivalent rotation matrix.")
.def("setFromTwoVectors", &setFromTwoVectors,
((bp::arg("self"), bp::arg("a"), bp::arg("b"))),
"Set *this to be the quaternion which transforms a into b through "
"a rotation.",
bp::return_self<>())
.def("conjugate", &Quaternion::conjugate, bp::arg("self"),
"Returns the conjugated quaternion.\n"
"The conjugate of a quaternion represents the opposite rotation.")
.def("inverse", &Quaternion::inverse, bp::arg("self"),
"Returns the quaternion describing the inverse rotation.")
.def("setIdentity", &Quaternion::setIdentity, bp::arg("self"),
"Set *this to the identity rotation.", bp::return_self<>())
.def("norm", &Quaternion::norm, bp::arg("self"),
"Returns the norm of the quaternion's coefficients.")
.def("normalize", &Quaternion::normalize, bp::arg("self"),
"Normalizes the quaternion *this.", bp::return_self<>())
.def("normalized", &normalized, bp::arg("self"),
"Returns a normalized copy of *this.",
bp::return_value_policy<bp::manage_new_object>())
.def("squaredNorm", &Quaternion::squaredNorm, bp::arg("self"),
"Returns the squared norm of the quaternion's coefficients.")
.def("dot", &Quaternion::template dot<Quaternion>,
(bp::arg("self"), bp::arg("other")),
"Returns the dot product of *this with an other Quaternion.\n"
"Geometrically speaking, the dot product of two unit quaternions "
"corresponds to the cosine of half the angle between the two "
"rotations.")
.def("_transformVector", &Quaternion::_transformVector,
(bp::arg("self"), bp::arg("vector")),
"Rotation of a vector by a quaternion.")
.def("vec", &vec, bp::arg("self"),
"Returns a vector expression of the imaginary part (x,y,z).")
.def("angularDistance",
// (bp::arg("self"),bp::arg("other")), // Bug in
// Boost.Python
&Quaternion::template angularDistance<Quaternion>,
"Returns the angle (in radian) between two rotations.")
.def("slerp", &slerp, bp::args("self", "t", "other"),
"Returns the spherical linear interpolation between the two "
"quaternions *this and other at the parameter t in [0;1].")
/* --- Operators --- */
.def(bp::self * bp::self)
.def(bp::self *= bp::self)
.def(bp::self * bp::other<Vector3>())
.def("__eq__", &QuaternionVisitor::__eq__)
.def("__ne__", &QuaternionVisitor::__ne__)
.def("__abs__", &Quaternion::norm)
.def("__len__", &QuaternionVisitor::__len__)
.def("__setitem__", &QuaternionVisitor::__setitem__)
.def("__getitem__", &QuaternionVisitor::__getitem__)
.def("assign", &assign<Quaternion>, bp::args("self", "quat"),
"Set *this from an quaternion quat and returns a reference to "
"*this.",
bp::return_self<>())
.def(
"assign",
(Quaternion & (Quaternion::*)(const AngleAxis&)) &
Quaternion::operator=,
bp::args("self", "aa"),
"Set *this from an angle-axis aa and returns a reference to *this.",
bp::return_self<>())
.def("__str__", &print)
.def("__repr__", &print)
// .def("FromTwoVectors",&Quaternion::template
// FromTwoVectors<Vector3,Vector3>,
// bp::args("a","b"),
// "Returns the quaternion which transform a into b through a
// rotation.")
.def("FromTwoVectors", &FromTwoVectors, bp::args("a", "b"),
"Returns the quaternion which transforms a into b through a "
"rotation.",
bp::return_value_policy<bp::manage_new_object>())
.staticmethod("FromTwoVectors")
.def("Identity", &Identity,
"Returns a quaternion representing an identity rotation.",
bp::return_value_policy<bp::manage_new_object>())
.staticmethod("Identity");
}
private:
static Quaternion* normalized(const Quaternion& self) {
return new Quaternion(self.normalized());
}
template <int i>
static void setCoeff(Quaternion& self, Scalar value) {
self.coeffs()[i] = value;
}
template <int i>
static Scalar getCoeff(Quaternion& self) {
return self.coeffs()[i];
}
static Quaternion& setFromTwoVectors(Quaternion& self, const Vector3& a,
const Vector3& b) {
return self.setFromTwoVectors(a, b);
}
template <typename OtherQuat>
static Quaternion& assign(Quaternion& self, const OtherQuat& quat) {
return self = quat;
}
static Quaternion* Identity() {
Quaternion* q(new Quaternion);
q->setIdentity();
return q;
}
static Quaternion* FromCoefficients(Scalar w, Scalar x, Scalar y, Scalar z) {
Quaternion* q(new Quaternion(w, x, y, z));
return q;
}
static Quaternion* FromAngleAxis(const AngleAxis& aa) {
Quaternion* q(new Quaternion(aa));
return q;
}
static Quaternion* FromTwoVectors(const Eigen::Ref<const Vector3> u,
const Eigen::Ref<const Vector3> v) {
Quaternion* q(new Quaternion);
q->setFromTwoVectors(u, v);
return q;
}
static Quaternion* FromOtherQuaternion(const Quaternion& other) {
Quaternion* q(new Quaternion(other));
return q;
}
static Quaternion* DefaultConstructor() { return new Quaternion; }
static Quaternion* FromOneVector(const Eigen::Ref<const Vector4> v) {
Quaternion* q(new Quaternion(v[3], v[0], v[1], v[2]));
return q;
}
static Quaternion* FromRotationMatrix(const Eigen::Ref<const Matrix3> R) {
Quaternion* q(new Quaternion(R));
return q;
}
static bool __eq__(const Quaternion& u, const Quaternion& v) {
return u.coeffs() == v.coeffs();
}
static bool __ne__(const Quaternion& u, const Quaternion& v) {
return !__eq__(u, v);
}
static Scalar __getitem__(const Quaternion& self, int idx) {
if ((idx < 0) || (idx >= 4)) throw eigenpy::ExceptionIndex(idx, 0, 3);
return self.coeffs()[idx];
}
static void __setitem__(Quaternion& self, int idx, const Scalar value) {
if ((idx < 0) || (idx >= 4)) throw eigenpy::ExceptionIndex(idx, 0, 3);
self.coeffs()[idx] = value;
}
static int __len__() { return 4; }
static Vector3 vec(const Quaternion& self) { return self.vec(); }
static std::string print(const Quaternion& self) {
std::stringstream ss;
ss << "(x,y,z,w) = " << self.coeffs().transpose() << std::endl;
return ss.str();
}
static Quaternion slerp(const Quaternion& self, const Scalar t,
const Quaternion& other) {
return self.slerp(t, other);
}
public:
static void expose() {
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 6
typedef EIGENPY_SHARED_PTR_HOLDER_TYPE(Quaternion) HolderType;
#else
typedef ::boost::python::detail::not_specified HolderType;
#endif
bp::class_<Quaternion, HolderType>(
"Quaternion",
"Quaternion representing rotation.\n\n"
"Supported operations "
"('q is a Quaternion, 'v' is a Vector3): "
"'q*q' (rotation composition), "
"'q*=q', "
"'q*v' (rotating 'v' by 'q'), "
"'q==q', 'q!=q', 'q[0..3]'.",
bp::no_init)
.def(QuaternionVisitor<Quaternion>())
.def(IdVisitor<Quaternion>());
// Cast to Eigen::QuaternionBase and vice-versa
bp::implicitly_convertible<Quaternion, QuaternionBase>();
// bp::implicitly_convertible<QuaternionBase,Quaternion >();
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_quaternion_hpp__
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2019, INRIA
*/
#ifndef __eigenpy_ref_hpp__
#define __eigenpy_ref_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/stride.hpp"
// For old Eigen versions, EIGEN_DEVICE_FUNC is not defined.
// We must define it just in the scope of this file.
#if !EIGEN_VERSION_AT_LEAST(3,2,90)
#define EIGEN_DEVICE_FUNC
#endif
namespace eigenpy
{
template<typename PlainObjectTypeT>
struct Ref
: Eigen::Ref<PlainObjectTypeT,EIGENPY_DEFAULT_ALIGNMENT_VALUE,typename StrideType<PlainObjectTypeT>::type>
{
public:
typedef Eigen::Ref<PlainObjectTypeT,EIGENPY_DEFAULT_ALIGNMENT_VALUE,typename eigenpy::template StrideType<PlainObjectTypeT>::type> Base;
private:
typedef Eigen::internal::traits<Base> Traits;
template<typename Derived>
EIGEN_DEVICE_FUNC inline Ref(const Eigen::PlainObjectBase<Derived>& expr,
typename Eigen::internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0);
public:
typedef typename Eigen::internal::traits<Base>::Scalar Scalar; /*!< \brief Numeric type, e.g. float, double, int or std::complex<float>. */ \
typedef typename Eigen::NumTraits<Scalar>::Real RealScalar; /*!< \brief The underlying numeric type for composed scalar types. \details In cases where Scalar is e.g. std::complex<T>, T were corresponding to RealScalar. */ \
typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */
typedef typename Eigen::internal::ref_selector<Base>::type Nested;
typedef typename Eigen::internal::traits<Base>::StorageKind StorageKind;
#if EIGEN_VERSION_AT_LEAST(3,2,90)
typedef typename Eigen::internal::traits<Base>::StorageIndex StorageIndex;
#else
typedef typename Eigen::internal::traits<Base>::Index StorageIndex;
#endif
enum { RowsAtCompileTime = Eigen::internal::traits<Base>::RowsAtCompileTime,
ColsAtCompileTime = Eigen::internal::traits<Base>::ColsAtCompileTime,
Flags = Eigen::internal::traits<Base>::Flags,
SizeAtCompileTime = Base::SizeAtCompileTime,
MaxSizeAtCompileTime = Base::MaxSizeAtCompileTime,
IsVectorAtCompileTime = Base::IsVectorAtCompileTime };
using Base::derived;
using Base::const_cast_derived;
typedef typename Base::PacketScalar PacketScalar;
template<typename Derived>
EIGEN_DEVICE_FUNC inline Ref(Eigen::PlainObjectBase<Derived>& expr,
typename Eigen::internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0)
: Base(expr.derived())
{}
template<typename Derived>
EIGEN_DEVICE_FUNC inline Ref(const Eigen::DenseBase<Derived>& expr,
typename Eigen::internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0)
: Base(expr.derived())
{}
#if EIGEN_COMP_MSVC_STRICT && (EIGEN_COMP_MSVC < 1900 || defined(__CUDACC_VER__)) // for older MSVC versions, as well as 1900 && CUDA 8, using the base operator is sufficient (cf Bugs 1000, 1324)
using Base::operator =;
#elif EIGEN_COMP_CLANG // workaround clang bug (see http://forum.kde.org/viewtopic.php?f=74&t=102653)
using Base::operator =; \
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Ref& operator=(const Ref& other) { Base::operator=(other); return *this; } \
template <typename OtherDerived> \
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Ref& operator=(const Eigen::DenseBase<OtherDerived>& other) { Base::operator=(other.derived()); return *this; }
#else
using Base::operator =; \
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Ref& operator=(const Ref& other) \
{ \
Base::operator=(other); \
return *this; \
}
#endif
}; // struct Ref<PlainObjectType>
}
#if !EIGEN_VERSION_AT_LEAST(3,2,90)
#undef EIGEN_DEVICE_FUNC
#endif
#endif // ifndef __eigenpy_ref_hpp__
//
// Copyright (c) 2020 INRIA
//
#ifndef __eigenpy_register_hpp__
#define __eigenpy_register_hpp__
#include <algorithm>
#include <map>
#include <string>
#include <typeinfo>
#include "eigenpy/exception.hpp"
#include "eigenpy/fwd.hpp"
#include "eigenpy/numpy.hpp"
namespace eigenpy {
/// \brief Structure collecting all the types registers in Numpy via 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>());
}
static bool isRegistered(PyTypeObject *py_type_ptr);
static int getTypeCode(PyTypeObject *py_type_ptr);
template <typename Scalar>
static PyTypeObject *getPyType() {
if (!isNumpyNativeType<Scalar>()) {
const PyTypeObject *const_py_type_ptr =
bp::converter::registered_pytype<Scalar>::get_pytype();
if (const_py_type_ptr == NULL) {
std::stringstream ss;
ss << "The type " << typeid(Scalar).name()
<< " does not have a registered converter inside Boot.Python."
<< std::endl;
throw std::invalid_argument(ss.str());
}
PyTypeObject *py_type_ptr = const_cast<PyTypeObject *>(const_py_type_ptr);
return py_type_ptr;
} else {
PyArray_Descr *new_descr =
call_PyArray_DescrFromType(NumpyEquivalentType<Scalar>::type_code);
return new_descr->typeobj;
}
}
template <typename Scalar>
static PyArray_Descr *getPyArrayDescr() {
if (!isNumpyNativeType<Scalar>()) {
return getPyArrayDescr(getPyType<Scalar>());
} else {
return call_PyArray_DescrFromType(NumpyEquivalentType<Scalar>::type_code);
}
}
template <typename Scalar>
static int getTypeCode() {
if (isNumpyNativeType<Scalar>())
return NumpyEquivalentType<Scalar>::type_code;
else {
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];
int code = instance().py_array_code_bindings[py_type];
return code;
} else
return -1; // type not registered
}
}
static int registerNewType(
PyTypeObject *py_type_ptr, const std::type_info *type_info_ptr,
const int type_size, const int alignment, PyArray_GetItemFunc *getitem,
PyArray_SetItemFunc *setitem, PyArray_NonzeroFunc *nonzero,
PyArray_CopySwapFunc *copyswap, PyArray_CopySwapNFunc *copyswapn,
PyArray_DotFunc *dotfunc, PyArray_FillFunc *fill,
PyArray_FillWithScalarFunc *fillwithscalar);
static Register &instance();
private:
Register() {};
struct Compare_PyTypeObject {
bool operator()(const PyTypeObject *a, const PyTypeObject *b) const {
return std::string(a->tp_name) < std::string(b->tp_name);
}
};
struct Compare_TypeInfo {
bool operator()(const std::type_info *a, const std::type_info *b) const {
return std::string(a->name()) < std::string(b->name());
}
};
typedef std::map<const std::type_info *, PyTypeObject *, Compare_TypeInfo>
MapInfo;
MapInfo type_to_py_type_bindings;
typedef std::map<PyTypeObject *, PyArray_Descr *, Compare_PyTypeObject>
MapDescr;
MapDescr py_array_descr_bindings;
typedef std::map<PyTypeObject *, int, Compare_PyTypeObject> MapCode;
MapCode py_array_code_bindings;
};
} // namespace eigenpy
#endif // __eigenpy_register_hpp__
......@@ -6,54 +6,72 @@
#ifndef __eigenpy_registration_hpp__
#define __eigenpy_registration_hpp__
#include <boost/python.hpp>
#include <boost/python/scope.hpp>
namespace eigenpy
{
///
/// \brief Check at runtime the registration of the type T inside the boost python registry.
///
/// \tparam T The type to check the registration.
///
/// \returns true if the type T is already registered.
///
template<typename T>
inline bool check_registration()
{
namespace bp = boost::python;
#include "eigenpy/fwd.hpp"
#include "eigenpy/registration_class.hpp"
namespace eigenpy {
///
/// \brief Check at runtime the registration of the type T inside the boost
/// python registry.
///
/// \tparam T The type to check the registration.
///
/// \returns true if the type T is already registered.
///
template <typename T>
inline bool check_registration() {
const bp::type_info info = bp::type_id<T>();
const bp::converter::registration* reg = bp::converter::registry::query(info);
if (reg == NULL)
return false;
else if ((*reg).m_to_python == NULL)
return false;
return true;
}
///
/// \brief Symlink to the current scope the already registered class T.
///
/// \returns true if the type T is effectively symlinked.
///
/// \tparam T The type to symlink.
///
template <typename T>
inline bool register_symbolic_link_to_registered_type() {
if (eigenpy::check_registration<T>()) {
const bp::type_info info = bp::type_id<T>();
const bp::converter::registration* reg = bp::converter::registry::query(info);
if (reg == NULL) return false;
else if ((*reg).m_to_python == NULL) return false;
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;
}
///
/// \brief Symlink to the current scope the already registered class T.
///
/// \returns true if the type T is effectively symlinked.
///
/// \tparam T The type to symlink.
///
template<typename T>
inline bool register_symbolic_link_to_registered_type()
{
namespace bp = boost::python;
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::scope().attr(reg->get_class_object()->tp_name) = bp::object(class_obj);
return true;
}
return false;
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__
#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-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 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 {};
} // 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__