...
 
Commits (224)
build*
release/
_build/
_release/
*~
Xcode/
*build*
......@@ -19,92 +19,65 @@ cache:
- make install
- cd work.$(hostname)/$(make show-var VARNAME=DISTNAME)
- make test
robotpkg-py-eigenpy-dubnium-release:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:dubnium
- make uninstall
robotpkg-py-eigenpy-16.04-release:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:16.04
image: memmos.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:16.04
robotpkg-py-eigenpy-18.04-release:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:18.04
robotpkg-py-eigenpy-py3-dubnium-release:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:dubnium
allow_failure: true
image: memmos.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:18.04
robotpkg-py-eigenpy-py3-16.04-release:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:16.04
allow_failure: true
image: memmos.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:16.04
robotpkg-py-eigenpy-py3-18.04-release:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:18.04
image: memmos.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:18.04
robotpkg-py-eigenpy-14.04-release:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:14.04
image: memmos.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:14.04
robotpkg-py-eigenpy-14.04-debug:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:14.04
image: memmos.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:14.04
before_script:
- echo PKG_OPTIONS.py-eigenpy=debug >> /opt/openrobots/etc/robotpkg.conf
robotpkg-py-eigenpy-py3-14.04-release:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:14.04
allow_failure: true
image: memmos.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:14.04
robotpkg-py-eigenpy-py3-14.04-debug:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:14.04
before_script:
- echo PKG_OPTIONS.py-eigenpy=debug >> /opt/openrobots/etc/robotpkg.conf
allow_failure: true
robotpkg-py-eigenpy-dubnium-debug:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:dubnium
image: memmos.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:14.04
before_script:
- echo PKG_OPTIONS.py-eigenpy=debug >> /opt/openrobots/etc/robotpkg.conf
robotpkg-py-eigenpy-py3-dubnium-debug:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:dubnium
before_script:
- echo PKG_OPTIONS.py-eigenpy=debug >> /opt/openrobots/etc/robotpkg.conf
allow_failure: true
robotpkg-py-eigenpy-16.04-debug:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:16.04
image: memmos.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:16.04
before_script:
- echo PKG_OPTIONS.py-eigenpy=debug >> /opt/openrobots/etc/robotpkg.conf
robotpkg-py-eigenpy-py3-16.04-debug:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:16.04
image: memmos.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:16.04
before_script:
- echo PKG_OPTIONS.py-eigenpy=debug >> /opt/openrobots/etc/robotpkg.conf
allow_failure: true
robotpkg-py-eigenpy-18.04-debug:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:18.04
image: memmos.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy:18.04
before_script:
- echo PKG_OPTIONS.py-eigenpy=debug >> /opt/openrobots/etc/robotpkg.conf
robotpkg-py-eigenpy-py3-18.04-debug:
<<: *robotpkg-py-eigenpy
image: eur0c.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:18.04
image: memmos.laas.fr:5000/stack-of-tasks/eigenpy/py-eigenpy-py3:18.04
before_script:
- echo PKG_OPTIONS.py-eigenpy=debug >> /opt/openrobots/etc/robotpkg.conf
language: python
python:
- "2.7"
- "3.5"
sudo: required
git:
depth: false
compiler:
- gcc
# - clang
......@@ -22,14 +21,28 @@ jobs:
include:
- dist: bionic
env: BUILDTYPE=Release
python: 2.7
- dist: bionic
env: BUILDTYPE=Release
python: 3.6
- dist: bionic
env: BUILDTYPE=Debug
python: 2.7
- dist: bionic
env: BUILDTYPE=Debug
python: 3.6
- dist: xenial
env: BUILDTYPE=Release
python: 2.7
- dist: xenial
env: BUILDTYPE=Debug
env: BUILDTYPE=Release
python: 3.5
- dist: trusty
env: BUILDTYPE=Debug
env: BUILDTYPE=Release
python: 2.7
- dist: trusty
env: BUILDTYPE=Release
python: 3.4
notifications:
email:
......@@ -43,7 +56,15 @@ before_install: ./.travis/run before_install
install: pip install coveralls numpy
script:
- export CMAKE_ADDITIONAL_OPTIONS="-DCMAKE_BUILD_TYPE=${BUILDTYPE}"
- sudo free -m -t
- ./.travis/run ../travis_custom/custom_build
- cd $TRAVIS_BUILD_DIR/unittest/cmake
- mkdir build
- cd build
- export CMAKE_PREFIX_PATH=/tmp/_ci/install
- cmake ..
- make
- ./extra_lib
- cd /tmp/_ci/build
- make uninstall
after_failure: ./.travis/run after_failure
after_success: ./.travis/run after_success
#
# Copyright (c) 2014-2019 CNRS
# Copyright (c) 2018-2019 INRIA
# Copyright (c) 2018-2020 INRIA
#
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
SET(PROJECT_NAME eigenpy)
SET(PROJECT_DESCRIPTION "Bindings between Numpy and Eigen using Boost.Python")
SET(PROJECT_URL "http://github.com/stack-of-tasks/eigenpy")
SET(PROJECT_USE_CMAKE_EXPORT TRUE)
SET(PROJECT_USE_KEYWORD_LINK_LIBRARIES TRUE)
SET(PROJECT_CUSTOM_HEADER_EXTENSION "hpp")
# Check if the submodule cmake have been initialized
IF(NOT EXISTS "${PROJECT_SOURCE_DIR}/cmake/base.cmake")
IF(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake/base.cmake")
MESSAGE(FATAL_ERROR "\nPlease run the following command first:\ngit submodule update --init\n")
ENDIF()
# Disable -Werror on Unix for now.
SET(CXX_DISABLE_WERROR True)
SET(CMAKE_VERBOSE_MAKEFILE True)
INCLUDE(cmake/base.cmake)
COMPUTE_PROJECT_ARGS(PROJECT_ARGS LANGUAGES CXX)
PROJECT(${PROJECT_NAME} ${PROJECT_ARGS})
INCLUDE(cmake/boost.cmake)
INCLUDE(cmake/python.cmake)
INCLUDE(cmake/ide.cmake)
INCLUDE(cmake/apple.cmake)
SET(PROJECT_NAME eigenpy)
SET(PROJECT_DESCRIPTION "Bindings between Numpy and Eigen using Boost.Python")
SET(PROJECT_URL "http://github.com/stack-of-tasks/eigenpy")
# Disable -Werror on Unix for now.
SET(CXX_DISABLE_WERROR True)
SET(CMAKE_VERBOSE_MAKEFILE True)
SETUP_PROJECT()
STRING(REPLACE "-pedantic" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
IF(APPLE)
SET(CMAKE_MACOSX_RPATH TRUE)
SET(CMAKE_SKIP_BUILD_RPATH FALSE)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
#SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir)
IF("${isSystemDir}" STREQUAL "-1")
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
ENDIF("${isSystemDir}" STREQUAL "-1")
ENDIF(APPLE)
# If needed, fix CMake policy for APPLE systems
APPLY_DEFAULT_APPLE_CONFIGURATION()
IF(WIN32)
SET(LINK copy_if_different)
......@@ -49,33 +45,37 @@ ENDIF(WIN32)
# --- OPTIONS ---------------------------------------
# ----------------------------------------------------
OPTION(INSTALL_DOCUMENTATION "Generate and install the documentation" FALSE)
OPTION(BUILD_UNIT_TESTS "Build the unitary tests" OFF)
IF(BUILD_UNIT_TESTS)
SET(BUILD_TESTING ON)
ELSE(BUILD_UNIT_TESTS)
SET(BUILD_TESTING OFF)
ENDIF(BUILD_UNIT_TESTS)
IF(DEFINED BUILD_UNIT_TESTS)
MESSAGE(AUTHOR_WARNING "BUILD_UNIT_TESTS is deprecated. Use BUILD_TESTING instead.\
If you are manually building Pinocchio from source in an existing build folder,\
we suggest that you delete your build folder and make a new one.")
SET(BUILD_TESTING ${BUILD_UNIT_TESTS})
ENDIF(DEFINED BUILD_UNIT_TESTS)
FINDPYTHON()
INCLUDE_DIRECTORIES(SYSTEM ${PYTHON_INCLUDE_DIRS})
FIND_NUMPY()
INCLUDE_DIRECTORIES(SYSTEM ${NUMPY_INCLUDE_DIRS})
IF(WIN32)
LINK_DIRECTORIES(${PYTHON_LIBRARY_DIRS})
ENDIF(WIN32)
# ----------------------------------------------------
# --- DEPENDANCIES -----------------------------------
# --- DEPENDENCIES -----------------------------------
# ----------------------------------------------------
ADD_REQUIRED_DEPENDENCY("eigen3 >= 3.0.5")
SET(BOOST_COMPONENTS python)
SEARCH_FOR_BOOST()
# Add Boost path to include directories.
INCLUDE_DIRECTORIES(SYSTEM ${Boost_INCLUDE_DIRS})
# ----------------------------------------------------
# --- INCLUDE ----------------------------------------
# ----------------------------------------------------
SET(${PROJECT_NAME}_UTILS_HEADERS
include/eigenpy/utils/scalar-name.hpp
include/eigenpy/utils/is-approx.hpp
)
SET(${PROJECT_NAME}_SOLVERS_HEADERS
include/eigenpy/solvers/solvers.hpp
include/eigenpy/solvers/preconditioners.hpp
......@@ -87,8 +87,19 @@ SET(${PROJECT_NAME}_SOLVERS_HEADERS
include/eigenpy/solvers/BFGSPreconditioners.hpp
)
SET(${PROJECT_NAME}_DECOMPOSITIONS_HEADERS
include/eigenpy/decompositions/decompositions.hpp
include/eigenpy/decompositions/EigenSolver.hpp
include/eigenpy/decompositions/LDLT.hpp
include/eigenpy/decompositions/LLT.hpp
include/eigenpy/decompositions/SelfAdjointEigenSolver.hpp
)
SET(${PROJECT_NAME}_HEADERS
${${PROJECT_NAME}_UTILS_HEADERS}
${${PROJECT_NAME}_SOLVERS_HEADERS}
${${PROJECT_NAME}_DECOMPOSITIONS_HEADERS}
include/eigenpy/computation-info.hpp
include/eigenpy/eigenpy.hpp
include/eigenpy/exception.hpp
include/eigenpy/expose.hpp
......@@ -98,18 +109,20 @@ SET(${PROJECT_NAME}_HEADERS
include/eigenpy/geometry.hpp
include/eigenpy/geometry-conversion.hpp
include/eigenpy/memory.hpp
include/eigenpy/numpy-type.hpp
include/eigenpy/registration.hpp
include/eigenpy/angle-axis.hpp
include/eigenpy/quaternion.hpp
include/eigenpy/stride.hpp
include/eigenpy/ref.hpp
include/eigenpy/details/rvalue_from_python_data.hpp
include/eigenpy/version.hpp
)
INCLUDE_DIRECTORIES(${${PROJECT_NAME}_BINARY_DIR}/include)
INCLUDE_DIRECTORIES(${${PROJECT_NAME}_SOURCE_DIR}/include)
LINK_DIRECTORIES(${PYTHON_LIBRARY_DIRS})
LIST(APPEND ${PROJECT_NAME}_HEADERS
${${PROJECT_NAME}_BINARY_DIR}/include/${PROJECT_NAME}/config.hpp
${${PROJECT_NAME}_BINARY_DIR}/include/${PROJECT_NAME}/deprecated.hpp
${${PROJECT_NAME}_BINARY_DIR}/include/${PROJECT_NAME}/warning.hpp)
# ----------------------------------------------------
# --- TARGETS ----------------------------------------
......@@ -119,35 +132,63 @@ SET(${PROJECT_NAME}_SOLVERS_SOURCES
src/solvers/solvers.cpp
)
SET(${PROJECT_NAME}_DECOMPOSITIONS_SOURCES
src/decompositions/decompositions.cpp
)
SET(${PROJECT_NAME}_SOURCES
${${PROJECT_NAME}_SOLVERS_SOURCES}
${${PROJECT_NAME}_DECOMPOSITIONS_SOURCES}
src/exception.cpp
src/eigenpy.cpp
src/matrix-float.cpp
src/matrix-complex-float.cpp
src/matrix-complex-double.cpp
src/matrix-double.cpp
src/matrix-long-double.cpp
src/matrix-complex-long-double.cpp
src/matrix-int.cpp
src/matrix-long.cpp
src/angle-axis.cpp
src/quaternion.cpp
src/geometry-conversion.cpp
src/version.cpp
)
ADD_LIBRARY(${PROJECT_NAME} SHARED ${${PROJECT_NAME}_SOURCES} ${${PROJECT_NAME}_HEADERS})
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}${PYTHON_SOABI}")
TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME}
SYSTEM PUBLIC
${Boost_INCLUDE_DIRS}
${EIGEN3_INCLUDE_DIRS}
${PYTHON_INCLUDE_DIRS}
${NUMPY_INCLUDE_DIRS}
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
IF(NOT WIN32)
TARGET_COMPILE_OPTIONS(${PROJECT_NAME} PRIVATE $<$<CXX_COMPILER_ID:MSVC>:-bigobj> "-Wno-conversion")
ELSE()
TARGET_COMPILE_OPTIONS(${PROJECT_NAME} PRIVATE $<$<CXX_COMPILER_ID:MSVC>:-bigobj>)
ENDIF()
TARGET_LINK_BOOST_PYTHON(${PROJECT_NAME})
TARGET_LINK_BOOST_PYTHON(${PROJECT_NAME} PUBLIC)
PKG_CONFIG_USE_DEPENDENCY(${PROJECT_NAME} eigen3)
INSTALL(TARGETS ${PROJECT_NAME}
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
EXPORT ${TARGETS_EXPORT_NAME}
PUBLIC_HEADER
INCLUDES DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
ADD_HEADER_GROUP(${PROJECT_NAME}_HEADERS)
ADD_SOURCE_GROUP(${PROJECT_NAME}_SOURCES)
INCLUDE(GenerateExportHeader)
GENERATE_EXPORT_HEADER(${PROJECT_NAME} EXPORT_FILE_NAME eigenpy/${PROJECT_NAME}_export.h)
TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME} INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>")
SET(PUBLIC_HEADER ${${PROJECT_NAME}_HEADERS})
# Install package for ROS
install(FILES package.xml DESTINATION share/eigenpy)
INSTALL(FILES
${CMAKE_CURRENT_BINARY_DIR}/eigenpy/${PROJECT_NAME}_export.h
DESTINATION include/eigenpy)
# ----------------------------------------------------
# --- PYTHON LIBRARY ---------------------------------
# ----------------------------------------------------
......@@ -162,5 +203,3 @@ PKG_CONFIG_APPEND_LIBS(${PROJECT_NAME})
PKG_CONFIG_APPEND_CFLAGS("-I${PYTHON_INCLUDE_DIRS}")
PKG_CONFIG_APPEND_CFLAGS("-I${NUMPY_INCLUDE_DIRS}")
PKG_CONFIG_APPEND_BOOST_LIBS(${BOOST_COMPONENTS})
SETUP_PROJECT_FINALIZE()
EigenPy
EigenPy — Python bindings between Numpy and Eigen
======
[![License](https://img.shields.io/badge/License-BSD%202--Clause-green.svg)](https://opensource.org/licenses/BSD-2-Clause)
[![Build Status](https://travis-ci.org/stack-of-tasks/eigenpy.svg?branch=devel)](https://travis-ci.org/stack-of-tasks/eigenpy)
[![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/eigenpy.svg)](https://anaconda.org/conda-forge/eigenpy)[![Conda Version](https://img.shields.io/conda/vn/conda-forge/eigenpy.svg)](https://anaconda.org/conda-forge/eigenpy)
[![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/eigenpy.svg)](https://anaconda.org/conda-forge/eigenpy)
[![Conda Version](https://img.shields.io/conda/vn/conda-forge/eigenpy.svg)](https://anaconda.org/conda-forge/eigenpy)
[![Anaconda-Server Badge](https://anaconda.org/conda-forge/eigenpy/badges/installer/conda.svg)](https://conda.anaconda.org/conda-forge)
......
Subproject commit f389aae203c4d92649cd5eb66289fd6a17c03fde
Subproject commit 61344038b1352d5a8de1e20db710c83be805d2eb
......@@ -8,7 +8,6 @@
#include "eigenpy/fwd.hpp"
#include <boost/python.hpp>
#include <Eigen/Core>
#include <Eigen/Geometry>
......@@ -19,18 +18,24 @@ namespace eigenpy
template<typename AngleAxis> class AngleAxisVisitor;
namespace internal
template<typename Scalar>
struct call< Eigen::AngleAxis<Scalar> >
{
template<typename Scalar>
struct call_expose< Eigen::AngleAxis<Scalar> >
typedef Eigen::AngleAxis<Scalar> AngleAxis;
static inline void expose()
{
typedef Eigen::AngleAxis<Scalar> type;
static inline void run()
{
AngleAxisVisitor<type>::expose();
}
};
} // namespace internal
AngleAxisVisitor<AngleAxis>::expose();
}
static inline bool isApprox(const AngleAxis & self, const AngleAxis & other,
const Scalar & prec = Eigen::NumTraits<Scalar>::dummy_precision())
{
return self.isApprox(other,prec);
}
};
BOOST_PYTHON_FUNCTION_OVERLOADS(isApproxAngleAxis_overload,call<Eigen::AngleAxisd>::isApprox,2,3)
template<typename AngleAxis>
class AngleAxisVisitor
......@@ -42,6 +47,7 @@ namespace eigenpy
typedef typename AngleAxis::Matrix3 Matrix3;
typedef typename Eigen::Quaternion<Scalar,0> Quaternion;
typedef Eigen::RotationBase<AngleAxis,3> RotationBase;
public:
......@@ -49,15 +55,15 @@ namespace eigenpy
void visit(PyClass& cl) const
{
cl
.def(bp::init<>("Default constructor"))
.def(bp::init<>(bp::arg("self"),"Default constructor"))
.def(bp::init<Scalar,Vector3>
((bp::arg("angle"),bp::arg("axis")),
((bp::arg("self"),bp::arg("angle"),bp::arg("axis")),
"Initialize from angle and axis."))
.def(bp::init<Matrix3>
((bp::arg("rotationMatrix")),
((bp::arg("self"),bp::arg("rotation matrix")),
"Initialize from a rotation matrix"))
.def(bp::init<Quaternion>(bp::arg("quaternion"),"Initialize from a quaternion."))
.def(bp::init<AngleAxis>(bp::arg("copy"),"Copy constructor."))
.def(bp::init<Quaternion>((bp::arg("self"),bp::arg("quaternion")),"Initialize from a quaternion."))
.def(bp::init<AngleAxis>((bp::arg("self"),bp::arg("copy")),"Copy constructor."))
/* --- Properties --- */
.add_property("axis",
......@@ -69,16 +75,25 @@ namespace eigenpy
&AngleAxisVisitor::setAngle,"The rotation angle.")
/* --- Methods --- */
.def("inverse",&AngleAxis::inverse,"Return the inverse rotation.")
.def("inverse",&AngleAxis::inverse,
bp::arg("self"),
"Return the inverse rotation.")
.def("fromRotationMatrix",&AngleAxis::template fromRotationMatrix<Matrix3>,
bp::arg("Sets *this from a 3x3 rotation matrix."),bp::return_self<>())
.def("toRotationMatrix",&AngleAxis::toRotationMatrix,"Constructs and returns an equivalent 3x3 rotation matrix.")
.def("matrix",&AngleAxis::matrix,"Returns an equivalent rotation matrix.")
.def("isApprox",(bool (AngleAxis::*)(const AngleAxis &))&AngleAxis::isApprox,
"Returns true if *this is approximately equal to other.")
.def("isApprox",(bool (AngleAxis::*)(const AngleAxis &, const Scalar prec))&AngleAxis::isApprox,
bp::args("other","prec"),
"Returns true if *this is approximately equal to other, within the precision determined by prec.")
(bp::arg("self"),bp::arg("rotation matrix")),
"Sets *this from a 3x3 rotation matrix",
bp::return_self<>())
.def("toRotationMatrix",
// bp::arg("self"),
&AngleAxis::toRotationMatrix,
"Constructs and returns an equivalent 3x3 rotation matrix.")
.def("matrix",&AngleAxis::matrix,
bp::arg("self"),
"Returns an equivalent rotation matrix.")
.def("isApprox",
&call<AngleAxis>::isApprox,
isApproxAngleAxis_overload(bp::args("self","other","prec"),
"Returns true if *this is approximately equal to other, within the precision determined by prec."))
/* --- Operators --- */
.def(bp::self * bp::other<Vector3>())
......@@ -101,7 +116,8 @@ namespace eigenpy
{ self.angle() = angle; }
static bool __eq__(const AngleAxis & u, const AngleAxis & v)
{ return u.isApprox(v); }
{ return u.axis() == v.axis() && v.angle() == u.angle(); }
static bool __ne__(const AngleAxis & u, const AngleAxis & v)
{ return !__eq__(u,v); }
......@@ -119,9 +135,12 @@ namespace eigenpy
static void expose()
{
bp::class_<AngleAxis>("AngleAxis",
"AngleAxis representation of rotations.\n\n",
"AngleAxis representation of a rotation.\n\n",
bp::no_init)
.def(AngleAxisVisitor<AngleAxis>());
// Cast to Eigen::RotationBase and vice-versa
bp::implicitly_convertible<AngleAxis,RotationBase>();
}
};
......
/*
* Copyright 2020 INRIA
*/
#ifndef __eigenpy_decompositions_computation_info_hpp__
#define __eigenpy_decompositions_computation_info_hpp__
#include <Eigen/Core>
#include <boost/python.hpp>
#include "eigenpy/config.hpp"
namespace eigenpy
{
inline void EIGENPY_DLLEXPORT exposeComputationInfo()
{
boost::python::enum_<Eigen::ComputationInfo>("ComputationInfo")
.value("Success",Eigen::Success)
.value("NumericalIssue",Eigen::NumericalIssue)
.value("NoConvergence",Eigen::NoConvergence)
.value("InvalidInput",Eigen::InvalidInput)
;
}
} // namespace eigenpy
#endif // define __eigenpy_decompositions_computation_info_hpp__
/*
* Copyright 2020 INRIA
*/
#ifndef __eigenpy_decomposition_eigen_solver_hpp__
#define __eigenpy_decomposition_eigen_solver_hpp__
#include <boost/python.hpp>
#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include "eigenpy/utils/scalar-name.hpp"
namespace eigenpy
{
template<typename _MatrixType>
struct EigenSolverVisitor
: public boost::python::def_visitor< EigenSolverVisitor<_MatrixType> >
{
typedef _MatrixType MatrixType;
typedef typename MatrixType::Scalar Scalar;
typedef Eigen::EigenSolver<MatrixType> Solver;
template<class PyClass>
void visit(PyClass& cl) const
{
namespace bp = boost::python;
cl
.def(bp::init<>("Default constructor"))
.def(bp::init<Eigen::DenseIndex>(bp::arg("size"),
"Default constructor with memory preallocation"))
.def(bp::init<MatrixType,bp::optional<bool> >(bp::args("matrix","compute_eigen_vectors"),
"Computes eigendecomposition of given matrix"))
.def("eigenvalues",&Solver::eigenvalues,bp::arg("self"),
"Returns the eigenvalues of given matrix.",
bp::return_value_policy<bp::return_by_value>())
.def("eigenvectors",&Solver::eigenvectors,bp::arg("self"),
"Returns the eigenvectors of given matrix.",
bp::return_value_policy<bp::return_by_value>())
.def("compute",&EigenSolverVisitor::compute_proxy<MatrixType>,
bp::args("self","matrix"),
"Computes the eigendecomposition of given matrix.",
bp::return_value_policy<bp::reference_existing_object>())
.def("compute",(Solver & (Solver::*)(const Eigen::EigenBase<MatrixType> & matrix, bool))&Solver::compute,
bp::args("self","matrix","compute_eigen_vectors"),
"Computes the eigendecomposition of given matrix.",
bp::return_value_policy<bp::reference_existing_object>())
.def("getMaxIterations",&Solver::getMaxIterations,bp::arg("self"),
"Returns the maximum number of iterations.")
.def("setMaxIterations",&Solver::setMaxIterations,bp::args("self","max_iter"),
"Sets the maximum number of iterations allowed.",
bp::return_value_policy<bp::reference_existing_object>())
.def("pseudoEigenvalueMatrix",&Solver::pseudoEigenvalueMatrix,bp::arg("self"),
"Returns the block-diagonal matrix in the pseudo-eigendecomposition.")
.def("pseudoEigenvectors",&Solver::pseudoEigenvectors ,bp::arg("self"),
"Returns the pseudo-eigenvectors of given matrix.",
bp::return_value_policy<bp::return_by_value>())
.def("info",&Solver::info,bp::arg("self"),
"NumericalIssue if the input contains INF or NaN values or overflow occured. Returns Success otherwise.")
;
}
static void expose()
{
static const std::string classname = "EigenSolver" + scalar_name<Scalar>::shortname();
expose(classname);
}
static void expose(const std::string & name)
{
namespace bp = boost::python;
bp::class_<Solver>(name.c_str(),
bp::no_init)
.def(EigenSolverVisitor());
}
private:
template<typename MatrixType>
static Solver & compute_proxy(Solver & self, const Eigen::EigenBase<MatrixType> & matrix)
{
return self.compute(matrix);
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_decomposition_eigen_solver_hpp__
/*
* Copyright 2020 INRIA
*/
#ifndef __eigenpy_decomposition_ldlt_hpp__
#define __eigenpy_decomposition_ldlt_hpp__
#include <boost/python.hpp>
#include <Eigen/Core>
#include <Eigen/Cholesky>
#include "eigenpy/utils/scalar-name.hpp"
namespace eigenpy
{
template<typename _MatrixType>
struct LDLTSolverVisitor
: public boost::python::def_visitor< LDLTSolverVisitor<_MatrixType> >
{
typedef _MatrixType MatrixType;
typedef typename MatrixType::Scalar Scalar;
typedef typename MatrixType::RealScalar RealScalar;
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1,MatrixType::Options> VectorType;
typedef Eigen::LDLT<MatrixType> Solver;
template<class PyClass>
void visit(PyClass& cl) const
{
namespace bp = boost::python;
cl
.def(bp::init<>("Default constructor"))
.def(bp::init<Eigen::DenseIndex>(bp::arg("size"),
"Default constructor with memory preallocation"))
.def(bp::init<MatrixType>(bp::arg("matrix"),
"Constructs a LDLT factorization from a given matrix."))
.def("isNegative",&Solver::isNegative,bp::arg("self"),
"Returns true if the matrix is negative (semidefinite).")
.def("isPositive",&Solver::isPositive,bp::arg("self"),
"Returns true if the matrix is positive (semidefinite).")
.def("matrixL",&matrixL,bp::arg("self"),
"Returns the lower triangular matrix L.")
.def("matrixU",&matrixU,bp::arg("self"),
"Returns the upper triangular matrix U.")
.def("vectorD",&vectorD,bp::arg("self"),
"Returns the coefficients of the diagonal matrix D.")
.def("transpositionsP",&transpositionsP,bp::arg("self"),
"Returns the permutation matrix P.")
.def("matrixLDLT",&Solver::matrixLDLT,bp::arg("self"),
"Returns the LDLT decomposition matrix.",
bp::return_value_policy<bp::return_by_value>())
.def("rankUpdate",(Solver & (Solver::*)(const Eigen::MatrixBase<VectorType> &, const RealScalar &))&Solver::template rankUpdate<VectorType>,
bp::args("self","vector","sigma"),
bp::return_value_policy<bp::reference_existing_object>() )
#if EIGEN_VERSION_AT_LEAST(3,3,0)
.def("adjoint",&Solver::adjoint,bp::arg("self"),
"Returns the adjoint, that is, a reference to the decomposition itself as if the underlying matrix is self-adjoint.",
bp::return_value_policy<bp::reference_existing_object>())
#endif
.def("compute",(Solver & (Solver::*)(const Eigen::EigenBase<MatrixType> & matrix))&Solver::compute,
bp::args("self","matrix"),
"Computes the LDLT of given matrix.",
bp::return_value_policy<bp::reference_existing_object>())
.def("info",&Solver::info,bp::arg("self"),
"NumericalIssue if the input contains INF or NaN values or overflow occured. Returns Success otherwise.")
#if EIGEN_VERSION_AT_LEAST(3,3,0)
.def("rcond",&Solver::rcond,bp::arg("self"),
"Returns an estimate of the reciprocal condition number of the matrix.")
#endif
.def("reconstructedMatrix",&Solver::reconstructedMatrix,bp::arg("self"),
"Returns the matrix represented by the decomposition, i.e., it returns the product: L L^*. This function is provided for debug purpose.")
.def("solve",&solve<VectorType>,bp::args("self","b"),
"Returns the solution x of A x = b using the current decomposition of A.")
.def("setZero",&Solver::setZero,bp::arg("self"),
"Clear any existing decomposition.")
;
}
static void expose()
{
static const std::string classname = "LDLT" + scalar_name<Scalar>::shortname();
expose(classname);
}
static void expose(const std::string & name)
{
namespace bp = boost::python;
bp::class_<Solver>(name.c_str(),
"Robust Cholesky decomposition of a matrix with pivoting.\n\n"
"Perform a robust Cholesky decomposition of a positive semidefinite or negative semidefinite matrix $ A $ such that $ A = P^TLDL^*P $, where P is a permutation matrix, L is lower triangular with a unit diagonal and D is a diagonal matrix.\n\n"
"The decomposition uses pivoting to ensure stability, so that L will have zeros in the bottom right rank(A) - n submatrix. Avoiding the square root on D also stabilizes the computation.",
bp::no_init)
.def(LDLTSolverVisitor());
}
private:
static MatrixType matrixL(const Solver & self) { return self.matrixL(); }
static MatrixType matrixU(const Solver & self) { return self.matrixU(); }
static VectorType vectorD(const Solver & self) { return self.vectorD(); }
static MatrixType transpositionsP(const Solver & self)
{
return self.transpositionsP() * MatrixType::Identity(self.matrixL().rows(),
self.matrixL().rows());
}
template<typename VectorType>
static VectorType solve(const Solver & self, const VectorType & vec)
{
return self.solve(vec);
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_decomposition_ldlt_hpp__
/*
* Copyright 2020 INRIA
*/
#ifndef __eigenpy_decomposition_llt_hpp__
#define __eigenpy_decomposition_llt_hpp__
#include <boost/python.hpp>
#include <Eigen/Core>
#include <Eigen/Cholesky>
#include "eigenpy/utils/scalar-name.hpp"
namespace eigenpy
{
template<typename _MatrixType>
struct LLTSolverVisitor
: public boost::python::def_visitor< LLTSolverVisitor<_MatrixType> >
{
typedef _MatrixType MatrixType;
typedef typename MatrixType::Scalar Scalar;
typedef typename MatrixType::RealScalar RealScalar;
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1,MatrixType::Options> VectorType;
typedef Eigen::LLT<MatrixType> Solver;
template<class PyClass>
void visit(PyClass& cl) const
{
namespace bp = boost::python;
cl
.def(bp::init<>("Default constructor"))
.def(bp::init<Eigen::DenseIndex>(bp::arg("size"),
"Default constructor with memory preallocation"))
.def(bp::init<MatrixType>(bp::arg("matrix"),
"Constructs a LLT factorization from a given matrix."))
.def("matrixL",&matrixL,bp::arg("self"),
"Returns the lower triangular matrix L.")
.def("matrixU",&matrixU,bp::arg("self"),
"Returns the upper triangular matrix U.")
.def("matrixLLT",&Solver::matrixLLT,bp::arg("self"),
"Returns the LLT decomposition matrix.",
bp::return_value_policy<bp::return_by_value>())
.def("rankUpdate",(Solver (Solver::*)(const VectorType &, const RealScalar &))&Solver::template rankUpdate<VectorType>,
bp::args("self","vector","sigma"))
#if EIGEN_VERSION_AT_LEAST(3,3,0)
.def("adjoint",&Solver::adjoint,bp::arg("self"),
"Returns the adjoint, that is, a reference to the decomposition itself as if the underlying matrix is self-adjoint.",
bp::return_value_policy<bp::reference_existing_object>())
#endif
.def("compute",(Solver & (Solver::*)(const Eigen::EigenBase<MatrixType> & matrix))&Solver::compute,
bp::args("self","matrix"),
"Computes the LLT of given matrix.",
bp::return_value_policy<bp::reference_existing_object>())
.def("info",&Solver::info,bp::arg("self"),
"NumericalIssue if the input contains INF or NaN values or overflow occured. Returns Success otherwise.")
#if EIGEN_VERSION_AT_LEAST(3,3,0)
.def("rcond",&Solver::rcond,bp::arg("self"),
"Returns an estimate of the reciprocal condition number of the matrix.")
#endif
.def("reconstructedMatrix",&Solver::reconstructedMatrix,bp::arg("self"),
"Returns the matrix represented by the decomposition, i.e., it returns the product: L L^*. This function is provided for debug purpose.")
.def("solve",&solve<VectorType>,bp::args("self","b"),
"Returns the solution x of A x = b using the current decomposition of A.")
;
}
static void expose()
{
static const std::string classname = "LLT" + scalar_name<Scalar>::shortname();
expose(classname);
}
static void expose(const std::string & name)
{
namespace bp = boost::python;
bp::class_<Solver>(name.c_str(),
"Standard Cholesky decomposition (LL^T) of a matrix and associated features.\n\n"
"This class performs a LL^T Cholesky decomposition of a symmetric, positive definite matrix A such that A = LL^* = U^*U, where L is lower triangular.\n\n"
"While the Cholesky decomposition is particularly useful to solve selfadjoint problems like D^*D x = b, for that purpose, we recommend the Cholesky decomposition without square root which is more stable and even faster. Nevertheless, this standard Cholesky decomposition remains useful in many other situations like generalised eigen problems with hermitian matrices.",
bp::no_init)
.def(LLTSolverVisitor());
}
private:
static MatrixType matrixL(const Solver & self) { return self.matrixL(); }
static MatrixType matrixU(const Solver & self) { return self.matrixU(); }
template<typename VectorType>
static VectorType solve(const Solver & self, const VectorType & vec)
{
return self.solve(vec);
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_decomposition_llt_hpp__
/*
* Copyright 2020 INRIA
*/
#ifndef __eigenpy_decomposition_self_adjoint_eigen_solver_hpp__
#define __eigenpy_decomposition_self_adjoint_eigen_solver_hpp__
#include <boost/python.hpp>
#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include "eigenpy/utils/scalar-name.hpp"
namespace eigenpy
{
template<typename _MatrixType>
struct SelfAdjointEigenSolverVisitor
: public boost::python::def_visitor< SelfAdjointEigenSolverVisitor<_MatrixType> >
{
typedef _MatrixType MatrixType;
typedef typename MatrixType::Scalar Scalar;
typedef Eigen::SelfAdjointEigenSolver<MatrixType> Solver;
template<class PyClass>
void visit(PyClass& cl) const
{
namespace bp = boost::python;
cl
.def(bp::init<>("Default constructor"))
.def(bp::init<Eigen::DenseIndex>(bp::arg("size"),
"Default constructor with memory preallocation"))
.def(bp::init<MatrixType,bp::optional<int> >(bp::args("matrix","options"),
"Computes eigendecomposition of given matrix"))
.def("eigenvalues",&Solver::eigenvalues,bp::arg("self"),
"Returns the eigenvalues of given matrix.",
bp::return_value_policy<bp::return_by_value>())
.def("eigenvectors",&Solver::eigenvectors,bp::arg("self"),
"Returns the eigenvectors of given matrix.",
bp::return_value_policy<bp::return_by_value>())
.def("compute",&SelfAdjointEigenSolverVisitor::compute_proxy<MatrixType>,
bp::args("self","matrix"),
"Computes the eigendecomposition of given matrix.",
bp::return_value_policy<bp::reference_existing_object>())
.def("compute",(Solver & (Solver::*)(const Eigen::EigenBase<MatrixType> & matrix, int options))&Solver::compute,
bp::args("self","matrix","options"),
"Computes the eigendecomposition of given matrix.",
bp::return_value_policy<bp::reference_existing_object>())
.def("computeDirect",&SelfAdjointEigenSolverVisitor::computeDirect_proxy,
bp::args("self","matrix"),
"Computes eigendecomposition of given matrix using a closed-form algorithm.",
bp::return_value_policy<bp::reference_existing_object>())
.def("computeDirect",(Solver & (Solver::*)(const MatrixType & matrix, int options))&Solver::computeDirect,
bp::args("self","matrix","options"),
"Computes eigendecomposition of given matrix using a closed-form algorithm.",
bp::return_value_policy<bp::reference_existing_object>())
.def("operatorInverseSqrt",&Solver::operatorInverseSqrt,bp::arg("self"),
"Computes the inverse square root of the matrix.",
bp::return_value_policy<bp::return_by_value>())
.def("operatorSqrt",&Solver::operatorSqrt,bp::arg("self"),
"Computes the inverse square root of the matrix.",
bp::return_value_policy<bp::return_by_value>())
.def("info",&Solver::info,bp::arg("self"),
"NumericalIssue if the input contains INF or NaN values or overflow occured. Returns Success otherwise.")
;
}
static void expose()
{
static const std::string classname = "SelfAdjointEigenSolver" + scalar_name<Scalar>::shortname();
expose(classname);
}
static void expose(const std::string & name)
{
namespace bp = boost::python;
bp::class_<Solver>(name.c_str(),
bp::no_init)
.def(SelfAdjointEigenSolverVisitor());
}
private:
template<typename MatrixType>
static Solver & compute_proxy(Solver & self, const Eigen::EigenBase<MatrixType> & matrix)
{
return self.compute(matrix);
}
static Solver & computeDirect_proxy(Solver & self, const MatrixType & matrix)
{
return self.computeDirect(matrix);
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_decomposition_self_adjoint_eigen_solver_hpp__
/*
* Copyright 2020 INRIA
*/
#ifndef __eigenpy_decompositions_decompositions_hpp__
#define __eigenpy_decompositions_decompositions_hpp__
#include "eigenpy/config.hpp"
namespace eigenpy
{
void EIGENPY_DLLEXPORT exposeDecompositions();
} // namespace eigenpy
#endif // define __eigenpy_decompositions_decompositions_hpp__
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2019, INRIA
* Copyright 2018-2020, INRIA
*/
#ifndef __eigenpy_details_hpp__
......@@ -10,23 +10,28 @@
#include "eigenpy/fwd.hpp"
#include <patchlevel.h> // For PY_MAJOR_VERSION
#include <numpy/arrayobject.h>
#include <iostream>
#include "eigenpy/eigenpy.hpp"
#include "eigenpy/numpy-type.hpp"
#include "eigenpy/registration.hpp"
#include "eigenpy/map.hpp"
#include "eigenpy/exception.hpp"
#define GET_PY_ARRAY_TYPE(array) PyArray_ObjectType(reinterpret_cast<PyObject *>(array), 0)
namespace eigenpy
{
template <typename SCALAR> struct NumpyEquivalentType {};
template <> struct NumpyEquivalentType<float> { enum { type_code = NPY_FLOAT };};
template <> struct NumpyEquivalentType< std::complex<float> > { enum { type_code = NPY_CFLOAT };};
template <> struct NumpyEquivalentType<double> { enum { type_code = NPY_DOUBLE };};
template <> struct NumpyEquivalentType< std::complex<double> > { enum { type_code = NPY_CDOUBLE };};
template <> struct NumpyEquivalentType<long double> { enum { type_code = NPY_LONGDOUBLE };};
template <> struct NumpyEquivalentType< std::complex<long double> > { enum { type_code = NPY_CLONGDOUBLE };};
template <> struct NumpyEquivalentType<int> { enum { type_code = NPY_INT };};
template <> struct NumpyEquivalentType<long> { enum { type_code = NPY_LONG };};
template <> struct NumpyEquivalentType<float> { enum { type_code = NPY_FLOAT };};
template <typename SCALAR1, typename SCALAR2>
struct FromTypeToType : public boost::false_type {};
......@@ -35,116 +40,105 @@ namespace eigenpy
template <> struct FromTypeToType<int,long> : public boost::true_type {};
template <> struct FromTypeToType<int,float> : public boost::true_type {};
template <> struct FromTypeToType<int,std::complex<float> > : public boost::true_type {};
template <> struct FromTypeToType<int,double> : public boost::true_type {};
template <> struct FromTypeToType<int,std::complex<double> > : public boost::true_type {};
template <> struct FromTypeToType<int,long double> : public boost::true_type {};
template <> struct FromTypeToType<int,std::complex<long double> > : public boost::true_type {};
template <> struct FromTypeToType<long,float> : public boost::true_type {};
template <> struct FromTypeToType<long,std::complex<float> > : public boost::true_type {};
template <> struct FromTypeToType<long,double> : public boost::true_type {};
template <> struct FromTypeToType<long,std::complex<double> > : public boost::true_type {};
template <> struct FromTypeToType<long,long double> : public boost::true_type {};
template <> struct FromTypeToType<long,std::complex<long double> > : public boost::true_type {};
template <> struct FromTypeToType<float,std::complex<float> > : public boost::true_type {};
template <> struct FromTypeToType<float,double> : public boost::true_type {};
template <> struct FromTypeToType<float,std::complex<double> > : public boost::true_type {};
template <> struct FromTypeToType<float,long double> : public boost::true_type {};
template <> struct FromTypeToType<float,std::complex<long double> > : public boost::true_type {};
template <> struct FromTypeToType<double,std::complex<double> > : public boost::true_type {};
template <> struct FromTypeToType<double,long double> : public boost::true_type {};
template <> struct FromTypeToType<double,std::complex<long double> > : public boost::true_type {};
namespace bp = boost::python;
enum NP_TYPE
{
DEFAULT_TYPE,
MATRIX_TYPE,
ARRAY_TYPE
};
struct NumpyType
template<typename MatType, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime>
struct initEigenObject
{
static NumpyType & getInstance()
static MatType * run(PyArrayObject * pyArray, void * storage)
{
static NumpyType instance;
return instance;
}
operator bp::object () { return CurrentNumpyType; }
assert(PyArray_NDIM(pyArray) == 1 || PyArray_NDIM(pyArray) == 2);
bp::object make(PyArrayObject* pyArray, bool copy = false)
{ return make((PyObject*)pyArray,copy); }
bp::object make(PyObject* pyObj, bool copy = false)
{
if (getType() == DEFAULT_TYPE) {
std::cerr <<
"eigenpy warning: you use the deprecated class numpy.matrix without explicily asking for it. "
"The default behaviour will change to numpy.array at next major release.\n"
"- Either call eigenpy.switchToNumpyMatrix() before using eigenpy to suppress this warning\n"
"- or call eigenpy.switchToNumpyArray() and adapt your code accordingly.\n"
"See https://github.com/stack-of-tasks/eigenpy/issues/87 for further details."
<< std::endl;
switchToNumpyMatrix();
int rows = -1, cols = -1;
if(PyArray_NDIM(pyArray) == 2)
{
rows = (int)PyArray_DIMS(pyArray)[0];
cols = (int)PyArray_DIMS(pyArray)[1];
}
bp::object m;
if(PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(CurrentNumpyType.ptr()),NumpyMatrixType))
m = NumpyMatrixObject(bp::object(bp::handle<>(pyObj)), bp::object(), copy);
// m = NumpyAsMatrixObject(bp::object(bp::handle<>(pyObj)));
else if(PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(CurrentNumpyType.ptr()),NumpyArrayType))
m = bp::object(bp::handle<>(pyObj)); // nothing to do here
Py_INCREF(m.ptr());
return m;
}
static void setNumpyType(bp::object & obj)
{
PyTypeObject * obj_type = PyType_Check(obj.ptr()) ? reinterpret_cast<PyTypeObject*>(obj.ptr()) : obj.ptr()->ob_type;
if(PyType_IsSubtype(obj_type,getInstance().NumpyMatrixType))
switchToNumpyMatrix();
else if(PyType_IsSubtype(obj_type,getInstance().NumpyArrayType))
switchToNumpyArray();
}
static void switchToNumpyArray()
{
getInstance().CurrentNumpyType = getInstance().NumpyArrayObject;
getType() = ARRAY_TYPE;
else if(PyArray_NDIM(pyArray) == 1)
{
rows = (int)PyArray_DIMS(pyArray)[0];
cols = 1;
}
return new (storage) MatType(rows,cols);
}
static void switchToNumpyMatrix()
};
template<typename MatType>
struct initEigenObject<MatType,true>
{
static MatType * run(PyArrayObject * pyArray, void * storage)
{
getInstance().CurrentNumpyType = getInstance().NumpyMatrixObject;
getType() = MATRIX_TYPE;
if(PyArray_NDIM(pyArray) == 1)
{
const int rows_or_cols = (int)PyArray_DIMS(pyArray)[0];
return new (storage) MatType(rows_or_cols);
}
else
{
const int rows = (int)PyArray_DIMS(pyArray)[0];
const int cols = (int)PyArray_DIMS(pyArray)[1];
return new (storage) MatType(rows,cols);
}
}
static NP_TYPE & getType()
};
template<typename Scalar, typename NewScalar, bool cast_is_valid = FromTypeToType<Scalar,NewScalar>::value >
struct CastMatToMat
{
template<typename MatrixIn, typename MatrixOut>
static void run(const Eigen::MatrixBase<MatrixIn> & input,
const Eigen::MatrixBase<MatrixOut> & dest)
{
static NP_TYPE np_type;
return np_type;
MatrixOut & dest_ = const_cast<MatrixOut &>(dest.derived());
if(dest.rows() == input.rows())
dest_ = input.template cast<NewScalar>();
else
dest_ = input.transpose().template cast<NewScalar>();
}
};
protected:
NumpyType()
template<typename Scalar, typename NewScalar>
struct CastMatToMat<Scalar,NewScalar,false>
{
template<typename MatrixIn, typename MatrixOut>
static void run(const Eigen::MatrixBase<MatrixIn> & /*input*/,
const Eigen::MatrixBase<MatrixOut> & /*dest*/)
{
pyModule = bp::import("numpy");
#if PY_MAJOR_VERSION >= 3
// TODO I don't know why this Py_INCREF is necessary.
// Without it, the destructor of NumpyType SEGV sometimes.
Py_INCREF(pyModule.ptr());
#endif
NumpyMatrixObject = pyModule.attr("matrix");
NumpyMatrixType = reinterpret_cast<PyTypeObject*>(NumpyMatrixObject.ptr());
NumpyArrayObject = pyModule.attr("ndarray");
NumpyArrayType = reinterpret_cast<PyTypeObject*>(NumpyArrayObject.ptr());
//NumpyAsMatrixObject = pyModule.attr("asmatrix");
//NumpyAsMatrixType = reinterpret_cast<PyTypeObject*>(NumpyAsMatrixObject.ptr());
CurrentNumpyType = NumpyMatrixObject; // default conversion
getType() = DEFAULT_TYPE;
// do nothing
assert("Must never happened");
}
bp::object CurrentNumpyType;
bp::object pyModule;
// Numpy types
bp::object NumpyMatrixObject; PyTypeObject * NumpyMatrixType;
//bp::object NumpyAsMatrixObject; PyTypeObject * NumpyAsMatrixType;
bp::object NumpyArrayObject; PyTypeObject * NumpyArrayType;
};
#define EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,Scalar,NewScalar,pyArray,mat) \
CastMatToMat<Scalar,NewScalar>::run(MapNumpy<MatType,Scalar>::map(pyArray),mat)
#define EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,NewScalar,mat,pyArray) \
CastMatToMat<Scalar,NewScalar>::run(mat,MapNumpy<MatType,NewScalar>::map(pyArray))
template<typename MatType>
struct EigenObjectAllocator
......@@ -154,39 +148,44 @@ namespace eigenpy
static void allocate(PyArrayObject * pyArray, void * storage)
{
const int rows = (int)PyArray_DIMS(pyArray)[0];
const int cols = (int)PyArray_DIMS(pyArray)[1];
Type * mat_ptr = new (storage) Type(rows,cols);
if(NumpyEquivalentType<Scalar>::type_code == GET_PY_ARRAY_TYPE(pyArray))
{
*mat_ptr = MapNumpy<MatType,Scalar>::map(pyArray); // avoid useless cast
return;
}
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
{
*mat_ptr = MapNumpy<MatType,int>::map(pyArray).template cast<Scalar>();
return;
}
Type * mat_ptr = initEigenObject<Type>::run(pyArray,storage);
Type & mat = *mat_ptr;
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
const int pyArray_Type = GET_PY_ARRAY_TYPE(pyArray);
if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code)
{
*mat_ptr = MapNumpy<MatType,long>::map(pyArray).template cast<Scalar>();
mat = MapNumpy<MatType,Scalar>::map(pyArray); // avoid useless cast
return;
}
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
switch(pyArray_Type)
{
*mat_ptr = MapNumpy<MatType,float>::map(pyArray).template cast<Scalar>();
return;
}
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
{
*mat_ptr = MapNumpy<MatType,double>::map(pyArray).template cast<Scalar>();
return;
case NPY_INT:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,int,Scalar,pyArray,mat);
break;
case NPY_LONG:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long,Scalar,pyArray,mat);
break;
case NPY_FLOAT:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,float,Scalar,pyArray,mat);
break;
case NPY_CFLOAT:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<float>,Scalar,pyArray,mat);
break;
case NPY_DOUBLE:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,double,Scalar,pyArray,mat);
break;
case NPY_CDOUBLE:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<double>,Scalar,pyArray,mat);
break;
case NPY_LONGDOUBLE:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,long double,Scalar,pyArray,mat);
break;
case NPY_CLONGDOUBLE:
EIGENPY_CAST_FROM_PYARRAY_TO_EIGEN_MATRIX(MatType,std::complex<long double>,Scalar,pyArray,mat);
break;
default:
throw Exception("You asked for a conversion which is not implemented.");
}
}
......@@ -196,35 +195,48 @@ namespace eigenpy
PyArrayObject * pyArray)
{
const MatrixDerived & mat = const_cast<const MatrixDerived &>(mat_.derived());
const int pyArray_Type = GET_PY_ARRAY_TYPE(pyArray);
if(NumpyEquivalentType<Scalar>::type_code == GET_PY_ARRAY_TYPE(pyArray))
{
MapNumpy<MatType,Scalar>::map(pyArray) = mat; // no cast needed
return;
}
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_INT)
{
MapNumpy<MatType,int>::map(pyArray) = mat.template cast<int>();
return;
}
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_LONG)
{
MapNumpy<MatType,long>::map(pyArray) = mat.template cast<long>();
return;
}
typedef typename MapNumpy<MatType,Scalar>::EigenMap MapType;
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_FLOAT)
if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code) // no cast needed
{
MapNumpy<MatType,float>::map(pyArray) = mat.template cast<float>();
MapType map_pyArray = MapNumpy<MatType,Scalar>::map(pyArray);
if(mat.rows() == map_pyArray.rows())
map_pyArray = mat;
else
map_pyArray = mat.transpose();
return;
}
if(GET_PY_ARRAY_TYPE(pyArray) == NPY_DOUBLE)
switch(pyArray_Type)
{
MapNumpy<MatType,double>::map(pyArray) = mat.template cast<double>();
return;
case NPY_INT:
EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,int,mat,pyArray);
break;
case NPY_LONG:
EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,long,mat,pyArray);
break;
case NPY_FLOAT:
EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,float,mat,pyArray);
break;
case NPY_CFLOAT:
EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,std::complex<float>,mat,pyArray);
break;
case NPY_DOUBLE:
EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,double,mat,pyArray);
break;
case NPY_CDOUBLE:
EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,std::complex<double>,mat,pyArray);
break;
case NPY_LONGDOUBLE:
EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,long double,mat,pyArray);
break;
case NPY_CLONGDOUBLE:
EIGENPY_CAST_FROM_EIGEN_MATRIX_TO_PYARRAY(MatType,Scalar,std::complex<long double>,mat,pyArray);
break;
default:
throw Exception("You asked for a conversion which is not implemented.");
}
}
};
......@@ -259,13 +271,14 @@ namespace eigenpy
typedef typename MatType::Scalar Scalar;
assert( (mat.rows()<INT_MAX) && (mat.cols()<INT_MAX)
&& "Matrix range larger than int ... should never happen." );