stack-of-tasks / eigenpy Goto Github PK
View Code? Open in Web Editor NEWEfficient bindings between Numpy and Eigen using Boost.Python
License: BSD 2-Clause "Simplified" License
Efficient bindings between Numpy and Eigen using Boost.Python
License: BSD 2-Clause "Simplified" License
This issue is about supporting python2 and python3 installation of eigenpy.
When compiling and installing eigenpy
, there are two libraries installed (assuming prefix=/opt/openrobots
here):
Note that the first one has a dependency on the libboost_python lib, in my example
$ ldd libeigenpy.so
linux-vdso.so.1 => (0x00007fffecf99000)
libboost_python-py35.so.1.58.0 => /usr/lib/x86_64-linux-gnu/libboost_python-py35.so.1.58.0 (0x00007f3e4e3c4000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f3e4e042000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f3e4dd39000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f3e4db23000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3e4d759000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f3e4d53c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3e4e8ca000)
(note the second line).
This dependency on libboost_python
from libeigenpy.so
creates troubles when trying to install eigenpy for python2 and python3 at the same time in the same folder.
As a workaround, I started to use a /opt/openrobots
and /opt/openrobots_py35
folder to separate the two installations of eigenpy
. However I am wondering if there is a more proper way to resolve this issue and wanted to report this in case someone else comes along the same issue.
I've implemented the complete share of memory between Eigen and Numpy without requiring any memory copy or allocation. I will suggest it as PR soon.
In the meantime, we need to decide in a similar way as #87 when to achieve the official switch.
I am setting up a new CI system and realised that installing robotpkg-py27-eigenpy
does not install libeigen3-dev
(i.e. does not depend on it).
Here is the output of dpkg
:
$ dpkg -s robotpkg-py27-eigenpy
Package: robotpkg-py27-eigenpy
Status: install ok installed
Priority: extra
Section: robotpkg/math
Maintainer: [email protected]
Architecture: amd64
Source: /opt/robotpkg/var/lib/robotpkg/packages/bsd/Ubuntu-16.04-x86_64/pub/py27-eigenpy-1.6.1.tgz
Version: 1.6.1
Replaces: robotpkg-py27-eigenpy
Provides: robotpkg-py27-eigenpy
Depends: libboost-python1.58-dev (>= 1.34.1), libboost-python1.58.0 (>= 1.34.1), libstdc++6 | libstdc++6, python-numpy (>= 1:1), python2.7-minimal (>= 2.7), python2.7-minimal (<< 2.8), libpython2.7-dev (>= 2.7), libpython2.7-dev (<< 2.8)
Conflicts: robotpkg-py35-eigenpy (= 1.4.5), robotpkg-py27-eigenpy (= 1.4.3), robotpkg-py35-eigenpy (= 1.4.1r1), robotpkg-py27-eigenpy (= 1.4.1), robotpkg-py27-eigenpy (= 1.4.1r1), robotpkg-py35-eigenpy (= 1.4.1), robotpkg-py27-eigenpy (= 1.6.0), robotpkg-py27-eigenpy (= 1.6.1), robotpkg-py27-eigenpy (= 1.4.4), robotpkg-py35-eigenpy (= 1.4.4), robotpkg-py35-eigenpy (= 1.4.3), robotpkg-py35-eigenpy (= 1.6.1), robotpkg-py35-eigenpy (= 1.4.2), robotpkg-py35-eigenpy (= 1.6.0), robotpkg-py35-eigenpy (= 1.5.1), robotpkg-py27-eigenpy (= 1.4.5), robotpkg-py35-eigenpy (= 1.5.0), robotpkg-py27-eigenpy (= 1.5.0), robotpkg-py35-eigenpy (= 1.4.2r1), robotpkg-py27-eigenpy (= 1.5.1), robotpkg-py35-eigenpy (= 1.4.1r2), robotpkg-py27-eigenpy (= 1.4.2r1), robotpkg-py27-eigenpy (= 1.4.1r2), robotpkg-py27-eigenpy (= 1.4.2), robotpkg-eigenpy (= 1.3.0), robotpkg-eigenpy (= 1.3.2), robotpkg-eigenpy (= 1.3.3), robotpkg-eigenpy (= 1.3.1r1), robotpkg-eigenpy (= 1.4.0), robotpkg-eigenpy (= 1.3.0r1), robotpkg-eigenpy (= 1.4.0r2), robotpkg-eigenpy (= 1.3.1), robotpkg-eigenpy (= 1.4.0r1), robotpkg-py27-eigenpy
Description: Eigen bindings to python
License: 2-clause-bsd
Debian-Packager: [email protected]
Bindings between numpy and eigen using boost::python
.
Homepage:
https://github.com/stack-of-tasks/eigenpy
Homepage: https://github.com/stack-of-tasks/eigenp
I think it should have the dependency to install libeigen3-dev
as it includes headers that depend on it. What do you think? @jcarpent @nim65s
From MoveIt (moveit/moveit#1536):
Instead upstream relies on pkg-config, but incidentally their pkgconfig file is broken too - it uses -isystem to include numpy which pkg-config --cflags-only-I eigenpy fails to extract.
Indeed, they are currently set as system includes:
Lines 53 to 55 in aacf998
And when running pkg-config --cflags-only-I eigenpy
, indeed the NumPy is missing. They do show up on pkg-config --cflags-only-other eigenpy
though, as expected.
Is there a specific reason to set them as SYSTEM
?
Edit: From CMake docs:
If the SYSTEM option is given, the compiler will be told the directories are meant as system include directories on some platforms. Signalling this setting might achieve effects such as the compiler skipping warnings, or these fixed-install system files not being considered in dependency calculations - see compiler docs.
Hi,
As shown by #34, we have random segfaults on python3:
https://gepgitlab.laas.fr/gsaurel/eigenpy/-/jobs/2812
Here is a minimal working exemple triggering this segfault:
import matrix
import numpy as np
m = np.reshape(range(64), (8, 8))
a = matrix.reflex(m, False)
print('end of script')
And here is what gdb finds:
(gdb) run python/test_mwe_segfault.py
Starting program: /usr/bin/python3 python/test_mwe_segfault.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff2f16700 (LWP 25047)]
[New Thread 0x7ffff0715700 (LWP 25048)]
[New Thread 0x7fffeff14700 (LWP 25049)]
[New Thread 0x7fffeb713700 (LWP 25050)]
[New Thread 0x7fffe8f12700 (LWP 25051)]
[New Thread 0x7fffe6711700 (LWP 25052)]
[New Thread 0x7fffe5f10700 (LWP 25053)]
end of script
Thread 1 "python3" received signal SIGSEGV, Segmentation fault.
0x00000000005a0ee8 in dict_dealloc.lto_priv.164 (mp=0x7ffff6955e48) at ../Objects/dictobject.c:1595
1595 ../Objects/dictobject.c: Aucun fichier ou dossier de ce type.
(gdb) bt
#0 0x00000000005a0ee8 in dict_dealloc.lto_priv.164 (mp=0x7ffff6955e48) at ../Objects/dictobject.c:1595
#1 0x0000000000597903 in module_dealloc.lto_priv () at ../Objects/moduleobject.c:638
#2 0x00007ffff64e3d57 in eigenpy::PyMatrixType::~PyMatrixType() ()
from /local/users/gsaurel/stack-of-tasks/eigenpy/libeigenpy.so
#3 0x00007ffff7829ff8 in __run_exit_handlers (status=0, listp=0x7ffff7bb45f8 <__exit_funcs>,
run_list_atexit=run_list_atexit@entry=true) at exit.c:82
#4 0x00007ffff782a045 in __GI_exit (status=<optimized out>) at exit.c:104
#5 0x00007ffff7810837 in __libc_start_main (main=0x4cfdd0 <main>, argc=2, argv=0x7fffffffd7a8, init=<optimized out>,
fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffd798) at ../csu/libc-start.c:325
#6 0x00000000005d6049 in _start ()
Following jrl-umi3218/jrl-cmakemodules#247, can we please add the necessary features to generate and install the cmake config such that the only requirements to use eigenpy reduce to:
find_package(eigenpy REQUIRED)
And can we please tag a release using the latest two PRs and this CMake configuration.
(I tried it following the comment in jrl-umi3218/jrl-cmakemodules#247, but didn't get it to install yet)
Hi Justin,
I have added this converter inside Crocoddyl (for more details see https://gepgitlab.laas.fr/loco-3d/crocoddyl/blob/cpp_devel/bindings/python/crocoddyl/utils.hpp).
I was thinking that maybe eigenpy is the right place for this code. What do you think?
If you agree with it, I could create a PR with these modifications.
Carlos
I try to bind a function whose prototype is f(Eigen::Ref)
. As far as I understand, this package only supports f(eigenpy::Ref)
. Am I right ?
I'was using Pinocchio with an installation of eigenpy (1.5.7) from source, and I got extra verbose output with the following statements:
call: EigenFromPy< Eigen::MatrixBase >::convertible
call: EigenFromPy< Eigen::MatrixBase >::construct
I found the cout statements in
eigenpy/include/eigenpy/details.hpp
Line 436 in 42ea7b3
eigenpy/include/eigenpy/details.hpp
Line 444 in 42ea7b3
Hello, I am trying to compile on Ubuntu 20.04 with noetic and I get this error:
/usr/include/boost/python/detail/destroy.hpp:20:9: error: ‘Eigen::MatrixBase::~MatrixBase() [with Derived = Eigen::Matrix<double, -1, 1>]’ is protected within this context
20 | p->~T();
| ^
In file included from /usr/include/eigen3/Eigen/Core:88,
from /home/emmanuel/moveit_ws/src/eigenpy/src/decompositions/decompositions.cpp:6:
/usr/include/eigen3/Eigen/src/Core/MatrixBase.h:468:5: note: declared protected here
468 | EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(MatrixBase)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
make[2]: *** [CMakeFiles/eigenpy.dir/build.make:92: CMakeFiles/eigenpy.dir/src/decompositions/decompositions.cpp.o] Error 1
If I change protected to public in /usr/include/eigen3/Eigen/src/Core/MatrixBase.h I get the additional error:
/usr/include/boost/python/detail/destroy.hpp:20:9: error: ‘Eigen::QuaternionBase::~QuaternionBase() [with Derived = Eigen::Quaternion]’ is protected within this context
20 | p->~T();
| ^
In file included from /usr/include/eigen3/Eigen/Core:88,
from /home/emmanuel/moveit_ws/src/eigenpy/include/eigenpy/fwd.hpp:11,
from /home/emmanuel/moveit_ws/src/eigenpy/include/eigenpy/quaternion.hpp:9,
from /home/emmanuel/moveit_ws/src/eigenpy/src/quaternion.cpp:8:
/usr/include/eigen3/Eigen/src/Geometry/Quaternion.h:188:3: note: declared protected here
188 | EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(QuaternionBase)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
make[2]: *** [CMakeFiles/eigenpy.dir/build.make:261: CMakeFiles/eigenpy.dir/src/quaternion.cpp.o] Error 1
In file included from /usr/include/eigenpy/fwd.hpp:14,
from /usr/include/eigenpy/eigenpy.hpp:9,
from /home/acxz/vcs/git/github/ros-noetic-arch/ros-noetic-moveit-ros-planning-interface/src/moveit-1.0.3/moveit_ros/planning_interface/move_group_interface/src/wrap_python_move_group.cpp:53:
/usr/include/eigenpy/numpy.hpp:15:10: fatal error: numpy/numpyconfig.h: No such file or directory
15 | #include <numpy/numpyconfig.h>
| ^~~~~~~~~~~~~~~~~~~~~
The following two scripts
a.py
:
import eigenpy
eigenpy.switchToNumpyArray()
b.py
:
import eigenpy
import a
print(eigenpy.getNumpyType()) # prints <class 'numpy.ndarray'>
Demonstrate that eigenpy's return type is a global setting which affects importing modules (I have no idea how it would act in a multi-threaded case, it would be interesting to know it).
This is displeasing, because it forces to either switch all of the codebase at once or to put a lot of pre-emptive switchToNumpyXXX
just to play on the safe side and be sure that the setting was not changed by another module.
I don't know whether it is doable or whether you agree with me, but would it be possible to limit the scope of switchToNumpyXXX
to the module where it is invoked?
Let's open the discussion to decide a timeline for using numpy arrays by default, instead of numpy matrices.
There are 2 patches in robotpkg. The first one has been put here by 8771002, and the second one is this:
- PyErr_SetObject(Exception::pyType,boost::python::object(e).ptr());
+ PyErr_SetString(PyExc_RuntimeError, e.what());
@jcarpent: could you put it here ? Otherwise I can do it, if you don't have time for that.
The goal is to make a new release, that will be used to move this package from robotpkg-wip to robotpkg.
I encounter a fatal assert (when using EigenPy in Pinocchio) when exposing a matrix of shape [1,1]. With a more precise context, I have a mass matrix for a 1-dof (pendulum) system in data.M that has a shape [1,1]. When accessing this matrix, I get an assert in debug mode, and a segfault (or various memory failure) in release mode.
Here is the copy of the assert:
python3: /eigenpy-1.6.13/include/eigenpy/map.hpp:44: static eigenpy::MapNumpyTraits<MatType, InputScalar, 0>::EigenMap eigenpy::MapNumpyTraits<MatType, InputScalar, 0>::mapImpl(PyArrayObject*) [with MatType = Eigen::Matrix<double, -1, -1>; InputScalar = double; eigenpy::MapNumpyTraits<MatType, InputScalar, 0>::EigenMap = Eigen::Map<Eigen::Matrix<double, -1, -1>, 0, Eigen::Stride<-1, -1> >; typename eigenpy::StrideType::type = Eigen::Stride<-1, -1>; PyArrayObject = tagPyArrayObject]: Assertion `PyArray_NDIM(pyArray) == 2' failed.
@nim65s prepared a docker to study the bug. Could you copy the instruction to run it? Many thanks for your help.
Dear all,
We will soon switch to BSD License v2.0 to ease our collaborations.
Let me know if there is a problem with this.
Cheers,
Olivier.
Hi,
There is a huge memory leak during the implicit conversion from numpy array to eigen matrix. Here is a script to reproduce the results on the attached figure.
import numpy as np
import pinocchio as pnc
pnc_model = pnc.buildModelFromUrdf('cartpole.txt')
pnc_data = pnc_model.createData()
q = np.zeros((2, 1))
v = np.zeros((2, 1))
for _ in range(10000000):
pnc.forwardKinematics(pnc_model, pnc_data, q, v)
valgrind --tool=massif python test.py
I hope it is possible to fix it.
Best
Sometimes, it might be useful to verify whether eigenpy is configured to convert Eigen objects to a numpy matrix or array. However, I cannot find a way to do it cleanly, particularly in Python.
I guess I can create a random Eigen object and check its type, but it would not be nice.
Is there a better way? If not, could you add a function such as isUsingNumpyArray
or isUsingNumpyMatrix
?
Hi,
after updating eigenpy to the latest devel commit ( b7865b8 ),
I realized that my previous python scripts needed a small modification to run without failure.
Before, I had a binded c++ method with signature :
void A(const Eigen::Vector3d&)
for instance called in python with:
bindedA(np.matrix([0.,1.,1.]) )
Now the same method must be called with a transpose to work:
bindedA(np.matrix([0.,1.,1.]).transpose() )
that is not a big issue, but I was just wondering if there was a reason for that and whether it
was achieved on purpose. Thanks
This is the source for the breakage between 1.6.9 and 2.1.2 that prevents updating the ROS release.
To reproduce (with latest devel):
find_package(eigenpy REQUIRED)
message(WARNING ${eigenpy_INCLUDE_DIRS})
This prints an empty message.
This issue is to track the issues with the eigenpy
package distributed via the ROS buildfarm on Ubuntu 16.04 which affects pinocchio
(regression, does not build) and moveit
(works because added eigenpyConfig.cmake
). Currently, only pinocchio
and other pkg-config consumers are broken.
Note: This problem only happens on 16.04/kinetic due to the old version of debhelper
.
GNUInstallDirs
. On the ros_buildfarm
, the CMAKE_INSTALL_FULL_LIBDIR
includes the system architecture for the pkg-config
file, while the library is correctly installed in lib/
.libdir
and pkglibdir
both include the system architecture:cat /opt/ros/kinetic/lib/x86_64-linux-gnu/pkgconfig/eigenpy.pc
prefix=/opt/ros/kinetic
exec_prefix=/opt/ros/kinetic
**libdir=/opt/ros/kinetic/lib/x86_64-linux-gnu**
bindir=/opt/ros/kinetic/bin
**pkglibdir=/opt/ros/kinetic/lib/x86_64-linux-gnu/eigenpy**
includedir=/opt/ros/kinetic/include
datarootdir=/opt/ros/kinetic/share
pkgdatarootdir=/opt/ros/kinetic/share
docdir=/opt/ros/kinetic/share/doc/eigenpy
doxygendocdir=/opt/ros/kinetic/share/doc/eigenpy/doxygen-html
Related issues:
@tfoote: Is there any way of resolving this apart from changing the rules
in the packaging manually (e.g. mrpt-ros-pkg-release/mrpt1-release@17361d7)? The most relevant answer to the issue here is from ros-infrastructure/ros_buildfarm#543 (comment)
When using eigenpy, flattening of arrays fails:
import numpy
v = numpy.array([1,2,3,4]).reshape(-1,1) # column vector
print v.flatten().shape # should result in (4,), but yields (4,1) when using eigenpy
Cf. jrl-umi3218/jrl-cmakemodules#324
The current master does not work on a freshly installed 18.04 due to the upstream changes in python.cmake
. Can we please revert the sync of the cmake submodule and make a patch release?
I found some numerical sensitivity problems in Eigenpy when I execute the same program again and again. I exposed the Dynamics module using boost python and when I try to call the ForwardDynamics or InverseDynamics functions in python, once in 20-30 times I get a strange answer as shown in the figure below. The first vector is the QDDot of 3 body system connected with revolute joints calculated using ForwardDynamics function and the second vector is Tau of the same system calculated with InverseDynamics function. However, calling the same program in C++ gives a very consistent output. Is it the problem with Eigenpy?
I'm not sure if I'm doing something wrong or if it's a real issue in eigenpy.
I am using the same C++ type (an Eigen::VectorXd
) for the return type and the parameter type of a binded method.
It is working well with Numpy matrix but when using eigenpy.switchToNumpyArray()
the returned array is of shape (x,)
while the array given as parameter must be of shape (x,1)
Right now I need to add .reshape(-1,1)
to all the arrays given as input to this kind of methods.
Is there something specific to define when doing the c++ binding such that the method can take array of shape (x,)
as parameters ?
A bind Eigen::Vector is converted into a column-Numpy array. This is not the default behaviour of Numpy. I suggest that we should stick to a row vector.
@jcarpent What is your though about it?
Hey guys,
I am building eigenpy and having fun debugging why it does not work. I am running gentoo and it feels like the installation path is sub-optimal. Is there a reason, why eigenpy needs to be installed to a system path, rather than user home dir, e.g. ~/.local/... ?
Thanks,
V
Would you mind releasing eigenpy
to ROS Noetic? It looks like all of its dependencies have been released, and recursively 41 repos need it.
I'm not sure how much work it will need. There is a guide about transitioning ROS packages to Python 3. The Noetic Migration Guide may have other changes this repo needs.
Hi all,
I am wonder it's possible to bind special matrices such as Eigen::DiagonalMatric<double, -1>? For sure, I can transform this matrices in my wrapping code to Eigen::MatrixXd, however, I am looking for a more elegant solution, if it's possible.
Right now eigenpy returns an np.matrix
. When returning a np.array
, I manage to get roughly 10x speedup on a simple benchmark. Also, I managed to improve the performance of computing the overall controller.
Therefore, how do you folks feel about returning np.array instead of np.matrix for performance reasons from eigenpy?
Here is the basic benchmark I did:
import time
import timeit
oMf = robot.data.oMf
obj = oMf[0]
a = (0., 0., 0.)
%timeit np.array(a)
%timeit np.matrix(a)
%timeit obj.translation
%timeit oMf[0].translation
### Returning np.matrix from eigenpy
#
# 872 ns ± 17.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
# 8.5 µs ± 46.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
# 5.04 µs ± 24.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
# 5.65 µs ± 45.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#
# ==> Sim + Control: 0.4053959846496582
### Returning np.array from eigenpy
# 793 ns ± 4.81 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
# 8.35 µs ± 155 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
# 353 ns ± 19.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
# 629 ns ± 9.26 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
#
# ==> Sim + Control: 0.2630190849304199
It seems that the symbols of libeigenpy are not well imported when there are exported in SHARED library: boost::python symbols are not well exported. A solution to fix the bug consists in making libeigenpy STATIC.
As noted in stack-of-tasks/pinocchio#653, we are working on packaging eigenpy and releasing it as binary via the ROS buildfarm, i.e., such that users can install it via sudo apt install ros-[kinetic/melodic]-eigenpy
. The status of the release pull requests is:
I will close this issue once the packages are available (~a few weeks).
The URL url = git://github.com/jrl-umi3218/jrl-cmakemodules.git
limits accessibility for many users.
Please apply same modifications as in stack-of-tasks/pinocchio#667
Hello, I have got an argument mismatch error when trying to run python/test_unit/test_eigenpy.py
:
ArgumentError: Python argument types in
matrix.reflex()
did not match C++ signature:
reflex(Eigen::Matrix<double, -1, -1, 0, -1, -1>, bool)
Specifically, this error occurred when the program was passing a numpy Matrix M
to the functioneigenpy.reflex(M,verbose)
. However the problem can be solved by replacing
const typename eigenpy::UnalignedEquivalent<MatType>::type & M
with const Eigen::MatrixXd & M
(i.e. specifying the argument type). There should be a bug in the Template definition.
Greetings,
I was just building ros_planning/moveit_ros/planning_interface and got this error:
-- Could not find the required component 'eigenpy'. The following CMake error indicates that you either need to install the package with the same name or change your environment so that it can be found.
CMake Error at /opt/ros/melodic/share/catkin/cmake/catkinConfig.cmake:83 (find_package):
Could not find a package configuration file provided by "eigenpy" with any
of the following names:
eigenpyConfig.cmake
eigenpy-config.cmake
Add the installation prefix of "eigenpy" to CMAKE_PREFIX_PATH or set
"eigenpy_DIR" to a directory containing one of the above files. If
"eigenpy" provides a separate development package or SDK, be sure it has
been installed.
Call Stack (most recent call first):
CMakeLists.txt:10 (find_package)
-- Configuring incomplete, errors occurred!
I have arch linux's eigenpy installed, but indeed I cannot find this file anywhere. I see some discussion on this file at eigenpy #69 and pinnochio #831, but not how to actually make the magic happen.
I also tried building from git via the instructions on this comment (using standard system targets, not the conda ones), but I don't see eigenpyConfig.cmake
anywhere in the directory tree.
Admittedly I know nothing about cmake, so please forgive if this is some simple setting. Like is the pkg-config.cmake
the same file, it's just not named definitively??
If it's helpful, here is how arch builds the package. If something needs to be changed, I can add a comment or file a report there to make it so.
Thanks for any tips.
There is a v1.6 tag which mirrors v1.6.6 - should the v1.6 be removed?
These lines
import eigenpy
q = eigenpy.Quaternion(1.,0.,0.,0.)
q.toRotationMatrix()
result in the following error
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-3-676a92d9f600> in <module>()
----> 1 q.toRotationMatrix()
AttributeError: 'Quaternion' object has no attribute 'toRotationMatrix'
I do not understand this, as I can clearly see in https://github.com/gabrielebndn/eigenpy/blob/72f57d877e2b9fb7b0d2d216ce947ad62073286f/include/eigenpy/quaternion.hpp#L106 that toRotationMatrix
is exposed, correctly, it seems.
What is weirder is that ipython
actually suggests toRotationMatrix
as an available method and auto-completes it, but then it gives an error as if it did not know it if you actually try to use it. What is going on?
This is not super-important as the same functionality is provided by the method matrix()
. The duplication comes from Eigen itself. The methods are inherited from RotationBase, where the documentation seems to suggest that the preferred method should be toRotationMatrix
, while matrix
was only "added to be conform with the Transform class' naming scheme." Further, in QuaternionBase only toRotationMatrix
is documented
I bound a C++ function foo
with Eigen::Matrix
arguments using EigenPy. I built a lib
which contains foo
. Then I import lib
in Python and foo
worked fine.
However, there is a problem when I insert import pinocchio as se3
before calling foo
in Python: Python will crash when the execution of foo
terminates, with the following error:
Python(34796,0x7fff9fcc5340) malloc: *** error for object 0x7fc61b61d020: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
I also observe that the problem occurs only when the input of foo
contains a Eigen::Matrix
object. The weird thing to me is the execution does not stop until the function call terminates.
Also note that the error occurs when pinocchio is imported, even if the inside of foo
does not call any pinocchio module.
You could check out this by binding a toy function (for example the reflex
function in issue #18 ) and import Pinocchio in Python. Many thanks for your help!
Depending on the compilation options, Eigen may use two different methods to allocate or deallocate dynamic matrices.
If libeigenpy and other Python libraries are compiled with two different set of options may lead to malloc segmentation fault.
This is for instance what happened in issue #19.
I proposed a fix to Eigen library (see https://bitbucket.org/eigen/eigen/pull-requests/354/fix-aligment-issue-with/diff for more details).
In the meantime, I suggest to inline enableEigenPy and to remove it from libeigenpy.
This is the message that I found:
[ 45%] Building CXX object CMakeFiles/eigenpy.dir/src/angle-axis.cpp.o
/usr/bin/c++ -Deigenpy_EXPORTS -I/home/cmastalli/devel/eigenpy/build -I/home/cmastalli/devel/eigenpy/build/include -I/home/cmastalli/devel/eigenpy/include -isystem /usr/local/include/eigen3 -isystem /usr/include/python2.7 -isystem /home/cmastalli/.local/lib/python2.7/site-packages/numpy/core/include -Wno-long-long -Wall -Wextra -Wcast-align -Wcast-qual -Wformat -Wwrite-strings -Wconversion -O3 -DNDEBUG -fPIC -Wno-conversion -o CMakeFiles/eigenpy.dir/src/angle-axis.cpp.o -c /home/cmastalli/devel/eigenpy/src/angle-axis.cpp
In file included from /home/cmastalli/devel/eigenpy/src/decompositions/decompositions.cpp:12:0:
/home/cmastalli/devel/eigenpy/include/eigenpy/decompositions/LLT.hpp: In instantiation of ‘void eigenpy::LLTSolverVisitor<_MatrixType>::visit(PyClass&) const [with PyClass = boost::python::class_<Eigen::LLT<Eigen::Matrix<double, -1, -1>, 1>, boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>; _MatrixType = Eigen::Matrix<double, -1, -1>]’:
/usr/include/boost/python/def_visitor.hpp:31:9: required from ‘static void boost::python::def_visitor_access::visit(const V&, classT&) [with V = boost::python::def_visitor<eigenpy::LLTSolverVisitor<Eigen::Matrix<double, -1, -1> > >; classT = boost::python::class_<Eigen::LLT<Eigen::Matrix<double, -1, -1>, 1>, boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>]’
/usr/include/boost/python/def_visitor.hpp:67:34: required from ‘void boost::python::def_visitor<DerivedVisitor>::visit(classT&) const [with classT = boost::python::class_<Eigen::LLT<Eigen::Matrix<double, -1, -1>, 1>, boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>; DerivedVisitor = eigenpy::LLTSolverVisitor<Eigen::Matrix<double, -1, -1> >]’
/usr/include/boost/python/class.hpp:221:9: required from ‘boost::python::class_<T, X1, X2, X3>::self& boost::python::class_<T, X1, X2, X3>::def(const boost::python::def_visitor<Derived>&) [with Derived = eigenpy::LLTSolverVisitor<Eigen::Matrix<double, -1, -1> >; W = Eigen::LLT<Eigen::Matrix<double, -1, -1>, 1>; X1 = boost::python::detail::not_specified; X2 = boost::python::detail::not_specified; X3 = boost::python::detail::not_specified; boost::python::class_<T, X1, X2, X3>::self = boost::python::class_<Eigen::LLT<Eigen::Matrix<double, -1, -1>, 1>, boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>]’
/home/cmastalli/devel/eigenpy/include/eigenpy/decompositions/LLT.hpp:83:7: required from ‘static void eigenpy::LLTSolverVisitor<_MatrixType>::expose(const string&) [with _MatrixType = Eigen::Matrix<double, -1, -1>; std::__cxx11::string = std::__cxx11::basic_string<char>]’
/home/cmastalli/devel/eigenpy/src/decompositions/decompositions.cpp:24:45: required from here
/home/cmastalli/devel/eigenpy/include/eigenpy/decompositions/LLT.hpp:47:25: error: no matches converting function ‘rankUpdate’ to type ‘eigenpy::LLTSolverVisitor<Eigen::Matrix<double, -1, -1> >::Solver (class Eigen::LLT<Eigen::Matrix<double, -1, -1>, 1>::*)(const VectorType&, const RealScalar&) {aka class Eigen::LLT<Eigen::Matrix<double, -1, -1>, 1> (class Eigen::LLT<Eigen::Matrix<double, -1, -1>, 1>::*)(const class Eigen::Matrix<double, -1, 1>&, const double&)}’
.def("rankUpdate",(Solver (Solver::*)(const VectorType &, const RealScalar &))&Solver::template rankUpdate<VectorType>,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/local/include/eigen3/Eigen/Cholesky:32:0,
from /usr/local/include/eigen3/Eigen/Eigenvalues:13,
from /home/cmastalli/devel/eigenpy/include/eigenpy/decompositions/EigenSolver.hpp:10,
from /home/cmastalli/devel/eigenpy/src/decompositions/decompositions.cpp:10:
/usr/local/include/eigen3/Eigen/src/Cholesky/LLT.h:208:11: note: candidate is: template<class VectorType> Eigen::LLT<_MatrixType, _UpLo>& Eigen::LLT<MatrixType, UpLo>::rankUpdate(const VectorType&, const RealScalar&) [with VectorType = VectorType; _MatrixType = Eigen::Matrix<double, -1, -1>; int _UpLo = 1]
LLT & rankUpdate(const VectorType& vec, const RealScalar& sigma = 1);
^~~~~~~~~~
When compiling eigenpy on Ubuntu 16.04 for python 3.5, the current repo setup found the libboost-python for python2.7. After bumping the cmake subrepo to the lastest master commit, the cmake found the proper libboost-python for python3.5.
Concerning the following error message, in debug mode:
eigenpy/include/eigenpy/details.hpp
Line 192 in f567b49
When I do SE3 * SE3 object, I get this warning because I guess it tries to find which SE3::operator* to use. In this case, it is not an error message.
Is there any cases where it is a real error ? If my understanding is correct, it is not a failure.
(Not sure filling this here is the correct place - feel free to tell me if there is a mailing list etc that is more suitable.)
Writing a small C++ <--> Python binding, I defined a hello
function and use eigenpy
as follows:
#include <eigenpy/eigenpy.hpp>
#include <boost/python.hpp>
#include <iostream>
void hello(const Eigen::VectorXd & state)
{
std::cout << "state[0]=" << state[0] << std::endl;
}
namespace bp = boost::python;
BOOST_PYTHON_MODULE(pin_hopper_simulator)
{
using namespace boost::python;
eigenpy::enableEigenPy();
bp::def("hello", hello,
bp::args("state"),
"Simple greeting"
);
}
This compiles fine. However, when running the following python code
import toy_hopper_compare.pin_hopper_simulator
import numpy as np
toy_hopper_compare.pin_hopper_simulator.hello(np.matrix([1, 2, 3]))
I get the error
jviereck@rams:toy_hopper_compare$ python test_binding.py
[[1 2 3]]
The internal type as no Eigen equivalent.
Traceback (most recent call last):
File "test_binding.py", line 10, in <module>
toy_hopper_compare.pin_hopper_simulator.hello(a)
Boost.Python.ArgumentError: Python argument types in
toy_hopper_compare.pin_hopper_simulator.hello(matrix)
did not match C++ signature:
hello(Eigen::Matrix<double, -1, 1, 0, -1, 1> state)
Any idea?
I would like to bind Eigen variables where I can read and write internal values, e.g.
# writing internal variables
myBindClass.data[0] = 2
myBindClass.data[:] = np.matrix(np.zeros(3))
For that, I used boost python and this is the code:
.add_property("data", bp::make_getter(&myBindClass::data, bp::return_value_policy<bp::return_by_value>()),
bp::make_setter(&myBindClass::data));
Despite that this c++ code allows me to write the entirely data, it doesn't allow me to write an specific internal data, i.e.
myBindClass.data = np.matrix(np.zeros(3)) # this works
myBindClass.data[0] = 3 # this doesn't work
myBindClass.data[:] = np.matrix(np.zeros(3)) # this doesn't work
myBindClass.data[0:2] = np.matrix(np.zeros(2)) # this doesn't work
Is there a solution provided by eigenpy?
Dear Justin,
Could we make a new release to have the new python fix on the master branch and ready for packaging.
Or do you see a major problem with that ?
All the best,
Olivier.
Not sure if it's a real issue or if I don't use it correctly, but I have two packages (namely pinocchio and curves) which call eigenpy::exposeQuaternion()
in their c++ code for python API.
The issue is that the python Quaternion
class only exist in the first package that I import, eg :
import pinocchio
import curves
pinocchio.Quaternion # ok
curves.Quaternion # do not exist
import curves
import pinocchio
pinocchio.Quaternion # do not exist
curves.Quaternion # OK
Is there a way to correctly manage this or should I always keep care of the import order ? It could lead to hard to catch error for future users of both packages.
Dear @seanyen,
The following lines:
Line 157 in 7c58249
// Handle portable symbol export.
// Defining manually which symbol should be exported is required
// under Windows whether MinGW or MSVC is used.
//
// The headers then have to be able to work in two different modes:
// - dllexport when one is building the library,
// - dllimport for clients using the library.
//
// On Linux, set the visibility accordingly. If C++ symbol visibility
// is handled by the compiler, see: http://gcc.gnu.org/wiki/Visibility
# if defined _WIN32 || defined __CYGWIN__
// On Microsoft Windows, use dllimport and dllexport to tag symbols.
# define EIGENPY_DLLIMPORT __declspec(dllimport)
# define EIGENPY_DLLEXPORT __declspec(dllexport)
# define EIGENPY_DLLLOCAL
# else
// On Linux, for GCC >= 4, tag symbols using GCC extension.
# if __GNUC__ >= 4
# define EIGENPY_DLLIMPORT __attribute__ ((visibility("default")))
# define EIGENPY_DLLEXPORT __attribute__ ((visibility("default")))
# define EIGENPY_DLLLOCAL __attribute__ ((visibility("hidden")))
# else
// Otherwise (GCC < 4 or another compiler is used), export everything.
# define EIGENPY_DLLIMPORT
# define EIGENPY_DLLEXPORT
# define EIGENPY_DLLLOCAL
# endif // __GNUC__ >= 4
# endif // defined _WIN32 || defined __CYGWIN__
# ifdef EIGENPY_STATIC
// If one is using the library statically, get rid of
// extra information.
# define EIGENPY_DLLAPI
# define EIGENPY_LOCAL
# else
// Depending on whether one is building or using the
// library define DLLAPI to import or export.
# ifdef eigenpy_EXPORTS
# define EIGENPY_DLLAPI EIGENPY_DLLEXPORT
# else
# define EIGENPY_DLLAPI EIGENPY_DLLIMPORT
# endif // EIGENPY_EXPORTS
# define EIGENPY_LOCAL EIGENPY_DLLLOCAL
# endif // EIGENPY_STATIC
#endif //! EIGENPY_CONFIG_HH
@seanyen Do you think that we can remove this generated file?
Can we tag the current master as 1.6.2 please? I'd like to make a release to the ROS buildfarm with the latest fixes and also change it to a proper third-party library, subsequently fixing now dependent packages (e.g. MoveIt) and get the package ready for the MEMMO deliverable.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.