diff --git a/CMakeLists.txt b/CMakeLists.txt
index d65f9d58d61537465e07df578644411cc9f12502..ea73ef4086d952dbaf28bc81230432739a50b036 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -74,6 +74,7 @@ SEARCH_FOR_BOOST()
 SET(${PROJECT_NAME}_UTILS_HEADERS
   include/eigenpy/utils/scalar-name.hpp
   include/eigenpy/utils/is-approx.hpp
+  include/eigenpy/utils/is-aligned.hpp
   )
 
 SET(${PROJECT_NAME}_SOLVERS_HEADERS
diff --git a/include/eigenpy/eigen-allocator.hpp b/include/eigenpy/eigen-allocator.hpp
index 243c1d3d4d1ba870c965af770cd11434cbf5b499..1a104a620898b89accb53409438b2cfcffd78022 100644
--- a/include/eigenpy/eigen-allocator.hpp
+++ b/include/eigenpy/eigen-allocator.hpp
@@ -8,6 +8,7 @@
 #include "eigenpy/fwd.hpp"
 #include "eigenpy/map.hpp"
 #include "eigenpy/scalar-conversion.hpp"
+#include "eigenpy/utils/is-aligned.hpp"
 
 namespace eigenpy
 {
@@ -17,7 +18,7 @@ namespace eigenpy
     template<typename MatType, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime>
     struct init_matrix_or_array
     {
-      static MatType * run(PyArrayObject * pyArray, void * storage)
+      static MatType * run(PyArrayObject * pyArray, void * storage = NULL)
       {
         assert(PyArray_NDIM(pyArray) == 1 || PyArray_NDIM(pyArray) == 2);
 
@@ -33,25 +34,34 @@ namespace eigenpy
           cols = 1;
         }
   
-        return new (storage) MatType(rows,cols);
+        if(storage)
+          return new (storage) MatType(rows,cols);
+        else
+          return new MatType(rows,cols);
       }
     };
 
     template<typename MatType>
     struct init_matrix_or_array<MatType,true>
     {
-      static MatType * run(PyArrayObject * pyArray, void * storage)
+      static MatType * run(PyArrayObject * pyArray, void * storage = NULL)
       {
         if(PyArray_NDIM(pyArray) == 1)
         {
           const int rows_or_cols = (int)PyArray_DIMS(pyArray)[0];
-          return new (storage) MatType(rows_or_cols);
+          if(storage)
+            return new (storage) MatType(rows_or_cols);
+          else
+            return new 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);
+          if(storage)
+            return new (storage) MatType(rows,cols);
+          else
+            return new MatType(rows,cols);
         }
       }
     };
@@ -79,7 +89,7 @@ namespace eigenpy
                       const Eigen::MatrixBase<MatrixOut> & /*dest*/)
       {
         // do nothing
-        assert("Must never happened");
+        assert(false && "Must never happened");
       }
     };
   
@@ -97,9 +107,11 @@ namespace eigenpy
     typedef MatType Type;
     typedef typename MatType::Scalar Scalar;
     
-    static void allocate(PyArrayObject * pyArray, void * storage)
+    static void allocate(PyArrayObject * pyArray,
+                         bp::converter::rvalue_from_python_storage<MatType> * storage)
     {
-      Type * mat_ptr = details::init_matrix_or_array<Type>::run(pyArray,storage);
+      void * raw_ptr = storage->storage.bytes;
+      Type * mat_ptr = details::init_matrix_or_array<Type>::run(pyArray,raw_ptr);
       Type & mat = *mat_ptr;
       
       const int pyArray_Type = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
@@ -193,6 +205,190 @@ namespace eigenpy
   };
   
 #if EIGEN_VERSION_AT_LEAST(3,2,0)
+  template<typename MatType, int Options, typename Stride>
+  struct EigenAllocator<Eigen::Ref<MatType,Options,Stride> >
+  {
+    typedef Eigen::Ref<MatType,Options,Stride> RefType;
+    typedef typename MatType::Scalar Scalar;
+
+    typedef typename ::boost::python::detail::referent_storage<RefType&>::StorageType StorageType;
+    
+    static void allocate(PyArrayObject * pyArray,
+                         bp::converter::rvalue_from_python_storage<RefType> * storage)
+    {
+      typedef typename StrideType<MatType,Eigen::internal::traits<RefType>::StrideType::InnerStrideAtCompileTime, Eigen::internal::traits<RefType>::StrideType::OuterStrideAtCompileTime >::type NumpyMapStride;
+
+      bool need_to_allocate = false;
+      const int pyArray_Type = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
+      if(pyArray_Type != NumpyEquivalentType<Scalar>::type_code)
+        need_to_allocate |= true;
+      if(    (MatType::IsRowMajor && (PyArray_IS_C_CONTIGUOUS(pyArray) && !PyArray_IS_F_CONTIGUOUS(pyArray)))
+          || (!MatType::IsRowMajor && (PyArray_IS_F_CONTIGUOUS(pyArray) && !PyArray_IS_C_CONTIGUOUS(pyArray)))
+          || MatType::IsVectorAtCompileTime
+          || (PyArray_IS_F_CONTIGUOUS(pyArray) && PyArray_IS_C_CONTIGUOUS(pyArray))) // no need to allocate
+        need_to_allocate |= false;
+      else
+        need_to_allocate |= true;
+      if(Options != Eigen::Unaligned) // we need to check whether the memory is correctly aligned and composed of a continuous segment
+      {
+        void * data_ptr = PyArray_DATA(pyArray);
+        if(!PyArray_ISONESEGMENT(pyArray) || !is_aligned(data_ptr,Options))
+          need_to_allocate |= true;
+      }
+      
+      void * raw_ptr = storage->storage.bytes;
+      if(need_to_allocate)
+      {
+        MatType * mat_ptr;
+        mat_ptr = details::init_matrix_or_array<MatType>::run(pyArray);
+        RefType mat_ref(*mat_ptr);
+        
+        new (raw_ptr) StorageType(mat_ref,pyArray,mat_ptr);
+        
+        RefType & mat = *reinterpret_cast<RefType*>(raw_ptr);
+        if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code)
+        {
+          mat = MapNumpy<MatType,Scalar>::map(pyArray); // avoid useless cast
+          return;
+        }
+        
+        switch(pyArray_Type)
+        {
+          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.");
+        }
+      }
+      else
+      {
+        assert(pyArray_Type == NumpyEquivalentType<Scalar>::type_code);
+        typename MapNumpy<MatType,Scalar,Options,NumpyMapStride>::EigenMap numpyMap = MapNumpy<MatType,Scalar,Options,NumpyMapStride>::map(pyArray);
+        RefType mat_ref(numpyMap);
+        new (raw_ptr) StorageType(mat_ref,pyArray);
+      }
+    }
+    
+    static void copy(RefType const & ref, PyArrayObject * pyArray)
+    {
+      EigenAllocator<MatType>::copy(ref,pyArray);
+    }
+  };
+
+  template<typename MatType, int Options, typename Stride>
+  struct EigenAllocator<const Eigen::Ref<const MatType,Options,Stride> >
+  {
+    typedef const Eigen::Ref<const MatType,Options,Stride> RefType;
+    typedef typename MatType::Scalar Scalar;
+
+    typedef typename ::boost::python::detail::referent_storage<RefType&>::StorageType StorageType;
+    
+    static void allocate(PyArrayObject * pyArray,
+                         bp::converter::rvalue_from_python_storage<RefType> * storage)
+    {
+      typedef typename StrideType<MatType,Eigen::internal::traits<RefType>::StrideType::InnerStrideAtCompileTime, Eigen::internal::traits<RefType>::StrideType::OuterStrideAtCompileTime >::type NumpyMapStride;
+
+      bool need_to_allocate = false;
+      const int pyArray_Type = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
+      if(pyArray_Type != NumpyEquivalentType<Scalar>::type_code)
+        need_to_allocate |= true;
+      if(    (MatType::IsRowMajor && (PyArray_IS_C_CONTIGUOUS(pyArray) && !PyArray_IS_F_CONTIGUOUS(pyArray)))
+          || (!MatType::IsRowMajor && (PyArray_IS_F_CONTIGUOUS(pyArray) && !PyArray_IS_C_CONTIGUOUS(pyArray)))
+          || MatType::IsVectorAtCompileTime
+          || (PyArray_IS_F_CONTIGUOUS(pyArray) && PyArray_IS_C_CONTIGUOUS(pyArray))) // no need to allocate
+        need_to_allocate |= false;
+      else
+        need_to_allocate |= true;
+      if(Options != Eigen::Unaligned) // we need to check whether the memory is correctly aligned and composed of a continuous segment
+      {
+        void * data_ptr = PyArray_DATA(pyArray);
+        if(!PyArray_ISONESEGMENT(pyArray) || !is_aligned(data_ptr,Options))
+          need_to_allocate |= true;
+      }
+      
+      void * raw_ptr = storage->storage.bytes;
+      if(need_to_allocate)
+      {
+        MatType * mat_ptr;
+        mat_ptr = details::init_matrix_or_array<MatType>::run(pyArray);
+        RefType mat_ref(*mat_ptr);
+        
+        new (raw_ptr) StorageType(mat_ref,pyArray,mat_ptr);
+        
+        MatType & mat = *mat_ptr;
+        if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code)
+        {
+          mat = MapNumpy<MatType,Scalar>::map(pyArray); // avoid useless cast
+          return;
+        }
+        
+        switch(pyArray_Type)
+        {
+          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.");
+        }
+      }
+      else
+      {
+        assert(pyArray_Type == NumpyEquivalentType<Scalar>::type_code);
+        typename MapNumpy<MatType,Scalar,Options,NumpyMapStride>::EigenMap numpyMap = MapNumpy<MatType,Scalar,Options,NumpyMapStride>::map(pyArray);
+        RefType mat_ref(numpyMap);
+        new (raw_ptr) StorageType(mat_ref,pyArray);
+      }
+    }
+    
+    static void copy(RefType const & ref, PyArrayObject * pyArray)
+    {
+      EigenAllocator<MatType>::copy(ref,pyArray);
+    }
+  };
+
   template<typename MatType>
   struct EigenAllocator< eigenpy::Ref<MatType> >
   {
diff --git a/include/eigenpy/eigen-from-python.hpp b/include/eigenpy/eigen-from-python.hpp
index c923079153e02cedf8eedd479955674927628e58..325326d6778bfdd743725b32a30e7efb527a726d 100644
--- a/include/eigenpy/eigen-from-python.hpp
+++ b/include/eigenpy/eigen-from-python.hpp
@@ -12,6 +12,103 @@
 
 #include <boost/python/converter/rvalue_from_python_data.hpp>
 
+namespace eigenpy
+{
+  namespace details
+  {
+    template<typename MatType, bool is_const = boost::is_const<MatType>::value>
+    struct copy_if_non_const
+    {
+      static void run(const Eigen::MatrixBase<MatType> & input,
+                      PyArrayObject * pyArray)
+      {
+        EigenAllocator<MatType>::copy(input,pyArray);
+      }
+    };
+  
+    template<typename MatType>
+    struct copy_if_non_const<const MatType,true>
+    {
+      static void run(const Eigen::MatrixBase<MatType> & /*input*/,
+                      PyArrayObject * /*pyArray*/)
+      {}
+    };
+  
+#if EIGEN_VERSION_AT_LEAST(3,2,0)
+    template<typename MatType, int Options, typename Stride> struct referent_storage_eigen_ref;
+  
+    template<typename MatType, int Options, typename Stride>
+    struct referent_storage_eigen_ref
+    {
+      typedef Eigen::Ref<MatType,Options,Stride> RefType;
+      
+      typedef ::boost::python::detail::aligned_storage<
+          ::boost::python::detail::referent_size<RefType&>::value
+      > AlignedStorage;
+      
+      referent_storage_eigen_ref()
+      : pyArray(NULL)
+      , mat_ptr(NULL)
+      , ref_ptr(reinterpret_cast<RefType*>(ref_storage.bytes))
+      {
+      }
+      
+      referent_storage_eigen_ref(const RefType & ref,
+                                 PyArrayObject * pyArray,
+                                 MatType * mat_ptr = NULL)
+      : pyArray(pyArray)
+      , mat_ptr(mat_ptr)
+      , ref_ptr(reinterpret_cast<RefType*>(ref_storage.bytes))
+      {
+        Py_INCREF(pyArray);
+        new (ref_storage.bytes) RefType(ref);
+      }
+      
+      ~referent_storage_eigen_ref()
+      {
+        if(mat_ptr != NULL && PyArray_ISWRITEABLE(pyArray))
+          copy_if_non_const<MatType>::run(*mat_ptr,pyArray);
+        
+        Py_DECREF(pyArray);
+          
+        if(mat_ptr != NULL)
+          mat_ptr->~MatType();
+        
+        ref_ptr->~RefType();
+      }
+ 
+      AlignedStorage ref_storage;
+      PyArrayObject * pyArray;
+      MatType * mat_ptr;
+      RefType * ref_ptr;
+    };
+#endif
+    
+  }
+}
+
+namespace boost { namespace python { namespace detail {
+#if EIGEN_VERSION_AT_LEAST(3,2,0)
+  template<typename MatType, int Options, typename Stride>
+  struct referent_storage<Eigen::Ref<MatType,Options,Stride> &>
+  {
+    typedef ::eigenpy::details::referent_storage_eigen_ref<MatType,Options,Stride> StorageType;
+    typedef aligned_storage<
+        ::boost::python::detail::referent_size<StorageType&>::value
+    > type;
+  };
+
+  template<typename MatType, int Options, typename Stride>
+  struct referent_storage<const Eigen::Ref<const MatType,Options,Stride> &>
+  {
+    typedef ::eigenpy::details::referent_storage_eigen_ref<const MatType,Options,Stride> StorageType;
+    typedef aligned_storage<
+        ::boost::python::detail::referent_size<StorageType&>::value
+    > type;
+  };
+#endif
+}}}
+
 namespace boost { namespace python { namespace converter {
 
   template<typename MatrixReference>
@@ -51,7 +148,6 @@ namespace boost { namespace python { namespace converter {
     }
   };
 
-
 #define RVALUE_FROM_PYTHON_DATA_INIT(type)                                 \
   typedef rvalue_from_python_data_eigen<type> Base;                        \
                                                                            \
@@ -79,10 +175,100 @@ namespace boost { namespace python { namespace converter {
 
 #undef RVALUE_FROM_PYTHON_DATA_INIT
 
+  template<typename MatType, int Options, typename Stride>
+  struct rvalue_from_python_data<Eigen::Ref<MatType,Options,Stride> &>
+  : rvalue_from_python_storage<Eigen::Ref<MatType,Options,Stride> &>
+  {
+    typedef Eigen::Ref<MatType,Options,Stride> T;
+
+# if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) \
+&& (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) \
+&& (!defined(__DECCXX_VER) || __DECCXX_VER > 60590014) \
+&& !defined(BOOST_PYTHON_SYNOPSIS) /* Synopsis' OpenCXX has trouble parsing this */
+    // This must always be a POD struct with m_data its first member.
+    BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage<T>,stage1) == 0);
+# endif
+
+    // The usual constructor
+    rvalue_from_python_data(rvalue_from_python_stage1_data const & _stage1)
+    {
+      this->stage1 = _stage1;
+    }
+
+    // This constructor just sets m_convertible -- used by
+    // implicitly_convertible<> to perform the final step of the
+    // conversion, where the construct() function is already known.
+    rvalue_from_python_data(void* convertible)
+    {
+      this->stage1.convertible = convertible;
+    }
+
+    // Destroys any object constructed in the storage.
+    ~rvalue_from_python_data()
+    {
+      typedef ::eigenpy::details::referent_storage_eigen_ref<MatType, Options,Stride> StorageType;
+      if (this->stage1.convertible == this->storage.bytes)
+        static_cast<StorageType *>((void *)this->storage.bytes)->~StorageType();
+    }
+  };
+
+  template<typename MatType, int Options, typename Stride>
+  struct rvalue_from_python_data<const Eigen::Ref<const MatType,Options,Stride> &>
+  : rvalue_from_python_storage<const Eigen::Ref<const MatType,Options,Stride> &>
+  {
+    typedef const Eigen::Ref<const MatType,Options,Stride> T;
+
+# if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) \
+&& (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) \
+&& (!defined(__DECCXX_VER) || __DECCXX_VER > 60590014) \
+&& !defined(BOOST_PYTHON_SYNOPSIS) /* Synopsis' OpenCXX has trouble parsing this */
+    // This must always be a POD struct with m_data its first member.
+    BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage<T>,stage1) == 0);
+# endif
+
+    // The usual constructor
+    rvalue_from_python_data(rvalue_from_python_stage1_data const & _stage1)
+    {
+      this->stage1 = _stage1;
+    }
+
+    // This constructor just sets m_convertible -- used by
+    // implicitly_convertible<> to perform the final step of the
+    // conversion, where the construct() function is already known.
+    rvalue_from_python_data(void* convertible)
+    {
+      this->stage1.convertible = convertible;
+    }
+
+    // Destroys any object constructed in the storage.
+    ~rvalue_from_python_data()
+    {
+      typedef ::eigenpy::details::referent_storage_eigen_ref<const MatType, Options,Stride> StorageType;
+      if (this->stage1.convertible == this->storage.bytes)
+        static_cast<StorageType *>((void *)this->storage.bytes)->~StorageType();
+    }
+  };
+
 } } }
 
 namespace eigenpy
 {
+
+  template<typename MatOrRefType>
+  void eigen_from_py_construct(PyObject* pyObj,
+                               bp::converter::rvalue_from_python_stage1_data* memory)
+  {
+    PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
+    assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX));
+    
+    bp::converter::rvalue_from_python_storage<MatOrRefType>* storage = reinterpret_cast<bp::converter::rvalue_from_python_storage<MatOrRefType>*>
+    (reinterpret_cast<void*>(memory));
+    
+    EigenAllocator<MatOrRefType>::allocate(pyArray,storage);
+
+    memory->convertible = storage->storage.bytes;
+  }
+
   template<typename MatType>
   struct EigenFromPy
   {
@@ -215,15 +401,7 @@ namespace eigenpy
   void EigenFromPy<MatType>::construct(PyObject* pyObj,
                                        bp::converter::rvalue_from_python_stage1_data* memory)
   {
-    PyArrayObject * pyArray = reinterpret_cast<PyArrayObject*>(pyObj);
-    assert((PyArray_DIMS(pyArray)[0]<INT_MAX) && (PyArray_DIMS(pyArray)[1]<INT_MAX));
-    
-    void* storage = reinterpret_cast<bp::converter::rvalue_from_python_storage<MatType>*>
-                   (reinterpret_cast<void*>(memory))->storage.bytes;
-    
-    EigenAllocator<MatType>::allocate(pyArray,storage);
-
-    memory->convertible = storage;
+    eigen_from_py_construct<MatType>(pyObj,memory);
   }
 
   template<typename MatType>
@@ -241,13 +419,23 @@ namespace eigenpy
     {
       EigenFromPy<MatType>::registration();
 
-      // Add also conversion to Eigen::MatrixBase<MatType>
+      // Add conversion to Eigen::MatrixBase<MatType>
       typedef Eigen::MatrixBase<MatType> MatrixBase;
       EigenFromPy<MatrixBase>::registration();
 
-      // Add also conversion to Eigen::EigenBase<MatType>
+      // Add conversion to Eigen::EigenBase<MatType>
       typedef Eigen::EigenBase<MatType> EigenBase;
       EigenFromPy<EigenBase>::registration();
+
+#if EIGEN_VERSION_AT_LEAST(3,2,0)
+      // Add conversion to Eigen::Ref<MatType>
+      typedef Eigen::Ref<MatType> RefType;
+      EigenFromPy<RefType>::registration();
+      
+      // Add conversion to Eigen::Ref<MatType>
+      typedef const Eigen::Ref<const MatType> ConstRefType;
+      EigenFromPy<ConstRefType>::registration();
+#endif
     }
   };
 
@@ -280,6 +468,51 @@ namespace eigenpy
   };
 
 #if EIGEN_VERSION_AT_LEAST(3,2,0)
+
+  template<typename MatType, int Options, typename Stride>
+  struct EigenFromPy<Eigen::Ref<MatType,Options,Stride> >
+  {
+    typedef Eigen::Ref<MatType,Options,Stride> RefType;
+    typedef typename MatType::Scalar Scalar;
+    
+    /// \brief Determine if pyObj can be converted into a MatType object
+    static void* convertible(PyArrayObject * pyArray)
+    {
+      if(!PyArray_Check(pyArray))
+        return 0;
+      if(!PyArray_ISWRITEABLE(pyArray))
+        return 0;
+      return EigenFromPy<MatType>::convertible(pyArray);
+    }
+    
+    static void registration()
+    {
+      bp::converter::registry::push_back
+      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
+       &eigen_from_py_construct<RefType>,bp::type_id<RefType>());
+    }
+  };
+
+  template<typename MatType, int Options, typename Stride>
+  struct EigenFromPy<const Eigen::Ref<const MatType,Options,Stride> >
+  {
+    typedef const Eigen::Ref<const MatType,Options,Stride> ConstRefType;
+    typedef typename MatType::Scalar Scalar;
+    
+    /// \brief Determine if pyObj can be converted into a MatType object
+    static void* convertible(PyArrayObject * pyArray)
+    {
+      return EigenFromPy<MatType>::convertible(pyArray);
+    }
+    
+    static void registration()
+    {
+      bp::converter::registry::push_back
+      (reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
+       &eigen_from_py_construct<ConstRefType>,bp::type_id<ConstRefType>());
+    }
+  };
+
   // Template specialization for Eigen::Ref
   template<typename MatType>
   struct EigenFromPyConverter< eigenpy::Ref<MatType> >
diff --git a/include/eigenpy/fwd.hpp b/include/eigenpy/fwd.hpp
index 3bc5937d05caebcd8be7c367693144acb31364b1..50a796e4ab634c070d09ab9b81e00571ec64416f 100644
--- a/include/eigenpy/fwd.hpp
+++ b/include/eigenpy/fwd.hpp
@@ -14,15 +14,13 @@
   #include "eigenpy/numpy.hpp"
 #undef NO_IMPORT_ARRAY
 
-#ifdef NPY_ALIGNED
 #if EIGEN_VERSION_AT_LEAST(3,2,90)
   #define EIGENPY_DEFAULT_ALIGNMENT_VALUE Eigen::Aligned16
 #else
   #define EIGENPY_DEFAULT_ALIGNMENT_VALUE Eigen::Aligned
 #endif
-#else
-  #define EIGENPY_DEFAULT_ALIGNMENT_VALUE Eigen::Unaligned
-#endif
+
+#define EIGENPY_NO_ALIGNMENT_VALUE Eigen::Unaligned
 
 #include "eigenpy/expose.hpp"
 
diff --git a/include/eigenpy/map.hpp b/include/eigenpy/map.hpp
index 487506cd0116e01b23fa622a223e737c8281dac0..33bc323129223a96343046ba1805761aa1731dd0 100644
--- a/include/eigenpy/map.hpp
+++ b/include/eigenpy/map.hpp
@@ -12,18 +12,17 @@
 
 namespace eigenpy
 {
-  template<typename MatType, typename InputScalar, bool IsVector>
+  template<typename MatType, typename InputScalar, int AlignmentValue, typename Stride, bool IsVector = MatType::IsVectorAtCompileTime>
   struct MapNumpyTraits {};
  
   /* Wrap a numpy::array with an Eigen::Map. No memory copy. */
-  template<typename MatType, typename InputScalar>
+  template<typename MatType, typename InputScalar, int AlignmentValue = EIGENPY_NO_ALIGNMENT_VALUE, typename Stride = typename StrideType<MatType>::type>
   struct MapNumpy
   {
-    typedef MapNumpyTraits<MatType, InputScalar, MatType::IsVectorAtCompileTime> Impl;
+    typedef MapNumpyTraits<MatType, InputScalar, AlignmentValue, Stride> Impl;
     typedef typename Impl::EigenMap EigenMap;
-    typedef typename Impl::Stride Stride;
 
-    static inline EigenMap map( PyArrayObject* pyArray );
+    static EigenMap map(PyArrayObject* pyArray);
    };
 
 } // namespace eigenpy
@@ -34,19 +33,23 @@ namespace eigenpy
 
 namespace eigenpy
 {
-  template<typename MatType, typename InputScalar>
-  struct MapNumpyTraits<MatType,InputScalar,false>
+  template<typename MatType, typename InputScalar, int AlignmentValue, typename Stride>
+  struct MapNumpyTraits<MatType,InputScalar,AlignmentValue,Stride,false>
   {
-    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;
+    typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime,MatType::Options> EquivalentInputMatrixType;
+    typedef Eigen::Map<EquivalentInputMatrixType,AlignmentValue,Stride> EigenMap;
 
-    static EigenMap mapImpl( PyArrayObject* pyArray )
+    static EigenMap mapImpl(PyArrayObject* pyArray)
     {
+      enum {
+        OuterStrideAtCompileTime = Stride::OuterStrideAtCompileTime,
+        InnerStrideAtCompileTime = Stride::InnerStrideAtCompileTime,
+      };
+      
       assert(PyArray_NDIM(pyArray) == 2 ||  PyArray_NDIM(pyArray) == 1);
     
       const long int itemsize = PyArray_ITEMSIZE(pyArray);
-      int stride1 = -1, stride2 = -1;
+      int inner_stride = -1, outer_stride = -1;
       int rows = -1, cols = -1;
       if(PyArray_NDIM(pyArray) == 2)
       {
@@ -57,8 +60,17 @@ namespace eigenpy
         
         rows = (int)PyArray_DIMS(pyArray)[0];
         cols = (int)PyArray_DIMS(pyArray)[1];
-        stride1 = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
-        stride2 = (int)PyArray_STRIDE(pyArray, 1) / (int)itemsize;
+        
+        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)
       {
@@ -68,33 +80,40 @@ namespace eigenpy
         rows = (int)PyArray_DIMS(pyArray)[0];
         cols = 1;
         
-        stride1 = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
-        stride2 = 0;
+        inner_stride = (int)PyArray_STRIDE(pyArray, 0) / (int)itemsize;
+        outer_stride = 0;
       }
       
-      Stride stride(stride2,stride1);
+      // Specific care for Eigen::Stride<-1,0>
+      if(InnerStrideAtCompileTime==0 && OuterStrideAtCompileTime==Eigen::Dynamic)
+      {
+        outer_stride = std::max(inner_stride,outer_stride); inner_stride = 0;
+      }
       
-      if( (MatType::RowsAtCompileTime!=rows)
-         && (MatType::RowsAtCompileTime!=Eigen::Dynamic) )
+      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) )
+      
+      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 );
+      return EigenMap(pyData, rows, cols, stride);
     }
   };
 
-  template<typename MatType, typename InputScalar>
-  struct MapNumpyTraits<MatType,InputScalar,true>
+  template<typename MatType, typename InputScalar, int AlignmentValue, typename Stride>
+  struct MapNumpyTraits<MatType,InputScalar,AlignmentValue,Stride,true>
   {
-    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;
+    typedef Eigen::Matrix<InputScalar,MatType::RowsAtCompileTime,MatType::ColsAtCompileTime,MatType::Options> EquivalentInputMatrixType;
+    typedef Eigen::Map<EquivalentInputMatrixType,AlignmentValue,Stride> EigenMap;
  
-    static EigenMap mapImpl( PyArrayObject* pyArray )
+    static EigenMap mapImpl(PyArrayObject* pyArray)
     {
       assert( PyArray_NDIM(pyArray) <= 2 );
 
@@ -110,8 +129,8 @@ namespace eigenpy
       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) )
+      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));
@@ -120,11 +139,11 @@ namespace eigenpy
     }
   };
 
-  template<typename MatType, typename InputScalar>
-  typename MapNumpy<MatType,InputScalar>::EigenMap
-  MapNumpy<MatType,InputScalar>::map(PyArrayObject * pyArray)
+  template<typename MatType, typename InputScalar, int AlignmentValue, typename Stride>
+  typename MapNumpy<MatType,InputScalar,AlignmentValue,Stride>::EigenMap
+  MapNumpy<MatType,InputScalar,AlignmentValue,Stride>::map(PyArrayObject * pyArray)
   {
-    return Impl::mapImpl(pyArray); 
+    return Impl::mapImpl(pyArray);
   }
 
 } // namespace eigenpy
diff --git a/include/eigenpy/numpy-allocator.hpp b/include/eigenpy/numpy-allocator.hpp
index 02a74215abe2dd198877dcb9c79b759eea33cff3..59885b37ebb5a3cc70f918e72e3aeb3f4088e360 100644
--- a/include/eigenpy/numpy-allocator.hpp
+++ b/include/eigenpy/numpy-allocator.hpp
@@ -50,6 +50,15 @@ namespace eigenpy
     }
   };
 
+#if EIGEN_VERSION_AT_LEAST(3,2,0)
+
+  template<typename MatType, int Options, typename Stride>
+  struct NumpyAllocator<Eigen::Ref<MatType,Options,Stride> > : NumpyAllocator<MatType &>
+  {
+  };
+
+#endif
+
   template<typename MatType>
   struct NumpyAllocator<const MatType &>
   {
@@ -69,6 +78,15 @@ namespace eigenpy
       return pyArray;
     }
   };
+
+#if EIGEN_VERSION_AT_LEAST(3,2,0)
+
+  template<typename MatType, int Options, typename Stride>
+  struct NumpyAllocator<const Eigen::Ref<const MatType,Options,Stride> > : NumpyAllocator<const MatType &>
+  {
+  };
+
+#endif
 }
 
 #endif // ifndef __eigenpy_numpy_allocator_hpp__
diff --git a/include/eigenpy/ref.hpp b/include/eigenpy/ref.hpp
index 4ffff43950e4e69fd0464267de8be8a4835c281c..c2eb21d5b6bbf0e7249183296327a121c829f945 100644
--- a/include/eigenpy/ref.hpp
+++ b/include/eigenpy/ref.hpp
@@ -20,10 +20,10 @@ namespace eigenpy
 
   template<typename PlainObjectTypeT>
   struct Ref
-  : Eigen::Ref<PlainObjectTypeT,EIGENPY_DEFAULT_ALIGNMENT_VALUE,typename StrideType<PlainObjectTypeT>::type>
+  : Eigen::Ref<PlainObjectTypeT,EIGENPY_NO_ALIGNMENT_VALUE,typename StrideType<PlainObjectTypeT>::type>
   {
   public:
-    typedef Eigen::Ref<PlainObjectTypeT,EIGENPY_DEFAULT_ALIGNMENT_VALUE,typename eigenpy::template StrideType<PlainObjectTypeT>::type> Base;
+    typedef Eigen::Ref<PlainObjectTypeT,EIGENPY_NO_ALIGNMENT_VALUE,typename eigenpy::template StrideType<PlainObjectTypeT>::type> Base;
 
   private:
     typedef Eigen::internal::traits<Base> Traits;
diff --git a/include/eigenpy/stride.hpp b/include/eigenpy/stride.hpp
index ab43349bf76647b8a14c1ecf1a9669f9b760eead..52f5656f1d36333aaafefcc2c971b0f70f04fe5d 100644
--- a/include/eigenpy/stride.hpp
+++ b/include/eigenpy/stride.hpp
@@ -10,17 +10,18 @@
 
 namespace eigenpy
 {
-  template<typename MatType, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime>
+  template<typename MatType, int InnerStride = Eigen::Dynamic, int OuterStride = Eigen::Dynamic, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime>
   struct StrideType
   {
-    typedef Eigen::Stride<Eigen::Dynamic,Eigen::Dynamic> type;
+    typedef Eigen::Stride<OuterStride,InnerStride> type;
   };
   
-  template<typename MatType>
-  struct StrideType<MatType,true>
+  template<typename MatType, int InnerStride, int OuterStride>
+  struct StrideType<MatType,InnerStride,OuterStride,true>
   {
-    typedef Eigen::InnerStride<Eigen::Dynamic> type;
+    typedef Eigen::InnerStride<InnerStride> type;
   };
+
 }
 
 #endif // ifndef __eigenpy_stride_hpp__
diff --git a/include/eigenpy/utils/is-aligned.hpp b/include/eigenpy/utils/is-aligned.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e87691158b76f249754f7844826e3914aced7b06
--- /dev/null
+++ b/include/eigenpy/utils/is-aligned.hpp
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 2020 INRIA
+//
+
+#ifndef __eigenpy_utils_is_aligned_hpp__
+#define __eigenpy_utils_is_aligned_hpp__
+
+namespace eigenpy
+{
+  inline bool is_aligned(void * ptr, std::size_t alignment)
+  {
+    return (reinterpret_cast<std::size_t>(ptr) & (alignment - 1)) == 0;
+  }
+}
+
+#endif
diff --git a/src/numpy.cpp b/src/numpy.cpp
index 4c76caef62ce2d8e7a14f5a2c7a06f14f081e4b0..61a91f33be39ce63481b51106637312804172773 100644
--- a/src/numpy.cpp
+++ b/src/numpy.cpp
@@ -13,6 +13,5 @@ namespace eigenpy
       PyErr_Print();
       PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import");
     }
-    //        std::cout << "init _import_array " << std::endl;
   }
 }
diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt
index 17bf479fe818ee27c9e0997c626b4399b797b4ef..1cb974d741f108bbee0267d401e272b17f67c2cd 100644
--- a/unittest/CMakeLists.txt
+++ b/unittest/CMakeLists.txt
@@ -34,13 +34,15 @@ ADD_LIB_UNIT_TEST(geometry "eigen3")
 ADD_LIB_UNIT_TEST(complex "eigen3")
 ADD_LIB_UNIT_TEST(return_by_ref "eigen3")
 IF(NOT ${EIGEN3_VERSION} VERSION_LESS "3.2.0")
-  ADD_LIB_UNIT_TEST(ref "eigen3")
+  ADD_LIB_UNIT_TEST(eigen_ref "eigen3")
+  ADD_LIB_UNIT_TEST(eigenpy_ref "eigen3")
 ENDIF()
 
 ADD_PYTHON_UNIT_TEST("py-matrix" "unittest/python/test_matrix.py" "unittest")
 ADD_PYTHON_UNIT_TEST("py-geometry" "unittest/python/test_geometry.py" "unittest")
 ADD_PYTHON_UNIT_TEST("py-complex" "unittest/python/test_complex.py" "unittest")
 ADD_PYTHON_UNIT_TEST("py-return-by-ref" "unittest/python/test_return_by_ref.py" "unittest")
+ADD_PYTHON_UNIT_TEST("py-eigen-ref" "unittest/python/test_eigen_ref.py" "unittest")
 
 ADD_PYTHON_UNIT_TEST("py-switch" "unittest/python/test_switch.py" "python/eigenpy")
 SET_TESTS_PROPERTIES("py-switch" PROPERTIES DEPENDS ${PYWRAP})
diff --git a/unittest/eigen_ref.cpp b/unittest/eigen_ref.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1e58cfee4c7760169a605a79f3547b4a43369081
--- /dev/null
+++ b/unittest/eigen_ref.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014-2019, CNRS
+ * Copyright 2018-2020, INRIA
+ */
+
+#include "eigenpy/eigenpy.hpp"
+#include <iostream>
+
+using namespace Eigen;
+using namespace eigenpy;
+
+template<typename MatType>
+void printMatrix(const Eigen::Ref<const MatType> mat)
+{
+  if(MatType::IsVectorAtCompileTime)
+    std::cout << "isVector" << std::endl;
+  std::cout << "size: cols " << mat.cols() << " rows " << mat.rows() << std::endl;
+  std::cout << mat << std::endl;
+}
+
+template<typename VecType>
+void printVector(const Eigen::Ref<const VecType> & vec)
+{
+  EIGEN_STATIC_ASSERT_VECTOR_ONLY(VecType);
+  printMatrix(vec);
+}
+
+template<typename MatType>
+void setOnes(Eigen::Ref<MatType> mat)
+{
+  mat.setOnes();
+}
+
+template<typename MatType>
+void fill(Eigen::Ref<MatType> mat, const typename MatType::Scalar & value)
+{
+  mat.fill(value);
+}
+
+BOOST_PYTHON_MODULE(eigen_ref)
+{
+  namespace bp = boost::python;
+  eigenpy::enableEigenPy();
+  
+  bp::def("printMatrix", printMatrix<Vector3d>);
+  bp::def("printMatrix", printMatrix<VectorXd>);
+  bp::def("printMatrix", printMatrix<MatrixXd>);
+  
+  bp::def("printVector", printVector<VectorXd>);
+  bp::def("printRowVector", printVector<RowVectorXd>);
+
+  bp::def("setOnes", setOnes<Vector3d>);
+  bp::def("setOnes", setOnes<VectorXd>);
+  bp::def("setOnes", setOnes<MatrixXd>);
+  
+  bp::def("fillVec3", fill<Vector3d>);
+  bp::def("fillVec", fill<VectorXd>);
+  bp::def("fill", fill<MatrixXd>);
+}
diff --git a/unittest/ref.cpp b/unittest/eigenpy_ref.cpp
similarity index 95%
rename from unittest/ref.cpp
rename to unittest/eigenpy_ref.cpp
index 094ae8590f6690b8e8fc0865c44175111058ba23..165e0d96402d5432c486cadfc8b509fbe6d40937 100644
--- a/unittest/ref.cpp
+++ b/unittest/eigenpy_ref.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright 2014-2019, CNRS
- * Copyright 2018-2019, INRIA
+ * Copyright 2018-2020, INRIA
  */
 
 #include "eigenpy/eigenpy.hpp"
@@ -37,9 +37,7 @@ void setOnes_wrap(eigenpy::Ref<MatType> mat)
   setOnes(mat);
 }
 
-
-
-BOOST_PYTHON_MODULE(ref)
+BOOST_PYTHON_MODULE(eigenpy_ref)
 {
   namespace bp = boost::python;
   eigenpy::enableEigenPy();
diff --git a/unittest/python/test_eigen_ref.py b/unittest/python/test_eigen_ref.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe8cd29e386162e52b5292681d6611f228532524
--- /dev/null
+++ b/unittest/python/test_eigen_ref.py
@@ -0,0 +1,16 @@
+import numpy as np
+from eigen_ref import *
+
+def test(mat):
+
+  printMatrix(mat)
+  fill(mat,1.)
+  printMatrix(mat)
+  assert np.array_equal(mat,np.full(mat.shape,1.))
+
+rows = 10
+cols = 30
+
+mat = np.array(np.zeros((rows,cols)))
+
+test(mat)