1
votes

I'm writing python wrapper for my project which uses Eigen for it's mathematical computations. After testing basic operations, eigen objects created inside python always return incorrect results. This usually happened to me when I didn't respect data alignments using Eigen. This is solved by allocating eigen objects using Eigen::aligned_allocator. How can I tell boost to allocate eigen objects using Eigen::aligned_allocator ?

Here's a simple test:

C++

using namespace boost::python;
using namespace Eigen;
class_<Isometry3d>("Isometry3d", init<>())
    .def("__str__", make_function(IsometryToStr)) 
    .def_readonly("Identity", Isometry3d::Identity())
;

IsometryToStr function simply uses operator << which is defined by the Eigen.

Python:

a = Isometry3d.Identity
print a

We would expect it to print the identity matrix, but the result is always different.

1
I had the same problem and I think I found a solution. I answered another similar question here : stackoverflow.com/a/29694518/116067 - Julien

1 Answers

1
votes

To control the allocation of C++ types, register a factory function as the Python object's constructor with make_constructor. Often times, custom allocation also implies custom deallocation, in which case boost::shared_ptr can be used to manage the lifetime of the object and invoke a custom dealloction strategy. This answer goes into more details, but here is a complete example with a basic custom allocator.

#include <cstdlib>
#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>

///  @brief Basic custom allocator.
template <typename T>
class custom_allocator
{
public:
  typedef size_t size_type;
  typedef T*     pointer;
  typedef T      value_type;
public:
  pointer allocate(size_type num, const void* hint = 0)
  {
    std::cout << "custom_allocator::allocate()" << std::endl;
    return reinterpret_cast<pointer>(
      std::malloc(num * sizeof(value_type)));
  }

  void deallocate(pointer p, size_type num)
  {
    std::cout << "custom_allocator::deallocate()" << std::endl;
    std::free(p);
  }
};

/// @brief Example class.
class foo
{
public:
  foo()         { std::cout << "foo()" << std::endl; }
  ~foo()        { std::cout << "~foo()" << std::endl; } 
  void action() { std::cout << "foo::action()" << std::endl; }
};

/// @brief Allocator for foo.
custom_allocator<foo> foo_allocator;

/// @brief Destroy a foo object.
void destroy_foo(foo* p)
{
  p->~foo();                      // Destruct.
  foo_allocator.deallocate(p, 1); // Deallocate.
}

/// @brief Factory function to create a foo object.
boost::shared_ptr<foo> create_foo()
{
  void* memory = foo_allocator.allocate(1); // Allocate.
  return boost::shared_ptr<foo>(
    new (memory) foo(), // Construct in allocated memory.
    &destroy_foo);      // Use custom deleter.
}

BOOST_PYTHON_MODULE(example) {
  namespace python = boost::python;
  // Expose foo, that will be managed by shared_ptr, and transparently
  // constructs the foo via a factory function to allow for a custom
  // deleter to use the custom allocator.
  python::class_<foo, boost::shared_ptr<foo>, 
                 boost::noncopyable>("Foo", python::no_init)
    .def("__init__", python::make_constructor(&create_foo))
    .def("action", &foo::action)
    ;
}

And the usage:

>>> import example
>>> f = example.Foo()
custom_allocator::allocate()
foo()
>>> f.action()
foo::action()
>>> f = None
~foo()
custom_allocator::deallocate()