diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt
index ecb95473c42eafff89d44d8a8a5b28cd2d37d639..598a853487b60051b73209b913e1faacc796a6b1 100644
--- a/benchmark/CMakeLists.txt
+++ b/benchmark/CMakeLists.txt
@@ -69,6 +69,13 @@ ADD_BENCH(timings-cholesky TRUE)
 # 
 ADD_BENCH(timings-derivatives TRUE)
 TARGET_LINK_LIBRARIES(timings-derivatives ${PROJECT_NAME})
+IF(CPPAD_FOUND)
+  PKG_CONFIG_USE_DEPENDENCY(timings-derivatives "cppad")
+ENDIF(CPPAD_FOUND)
+IF(CPPADCG_FOUND)
+  SET_PROPERTY(TARGET timings-derivatives PROPERTY CXX_STANDARD 11)
+  PKG_CONFIG_USE_DEPENDENCY(timings-derivatives "cppadcg")
+ENDIF(CPPADCG_FOUND)
 
 # timings-eigen
 # 
diff --git a/benchmark/timings-derivatives.cpp b/benchmark/timings-derivatives.cpp
index 5d7b090293e05f72b21afb06e3b6014b00e58fb3..b65693c35f27df336fc635b660c774b7b054e79b 100644
--- a/benchmark/timings-derivatives.cpp
+++ b/benchmark/timings-derivatives.cpp
@@ -15,11 +15,6 @@
 // Pinocchio If not, see
 // <http://www.gnu.org/licenses/>.
 
-#include "pinocchio/spatial/fwd.hpp"
-#include "pinocchio/spatial/se3.hpp"
-#include "pinocchio/multibody/visitor.hpp"
-#include "pinocchio/multibody/model.hpp"
-#include "pinocchio/multibody/data.hpp"
 #include "pinocchio/algorithm/joint-configuration.hpp"
 #include "pinocchio/algorithm/kinematics.hpp"
 #include "pinocchio/algorithm/kinematics-derivatives.hpp"
@@ -37,14 +32,199 @@
 
 #include "pinocchio/utils/timer.hpp"
 
+template<typename _Scalar, typename _EvalScalar = _Scalar>
+struct AutoDiffRNEA
+{
+  typedef _Scalar Scalar;
+  typedef CppAD::AD<Scalar> ADScalar;
+  typedef _EvalScalar EvalScalar;
+  enum { Options = 0 };
+  
+  typedef se3::ModelTpl<Scalar,Options> Model;
+  typedef se3::DataTpl<Scalar,Options> Data;
+  typedef se3::ModelTpl<EvalScalar,Options> EvalModel;
+  typedef se3::DataTpl<EvalScalar,Options> EvalData;
+  typedef se3::ModelTpl<ADScalar,Options> ADModel;
+  typedef se3::DataTpl<ADScalar,Options> ADData;
+  
+  typedef Eigen::Matrix<EvalScalar,Eigen::Dynamic,Eigen::Dynamic,Options> MatrixXs;
+  typedef Eigen::Matrix<EvalScalar,Eigen::Dynamic,1,Options> VectorXs;
+  typedef Eigen::Matrix<ADScalar,Eigen::Dynamic,1,Options> ADVectorXs;
+  
+  typedef typename ADModel::ConfigVectorType ADCongigVectorType;
+  typedef typename ADModel::TangentVectorType ADTangentVectorType;
+  
+  typedef CppAD::ADFun<Scalar> ADFun;
+  
+  template<typename OtherScalar>
+  AutoDiffRNEA(const se3::ModelTpl<OtherScalar,Options> & model)
+  : drnea_dq(model.nv,model.nv)
+  , drnea_dv(model.nv,model.nv)
+  , drnea_da(model.nv,model.nv)
+  , ad_model(model.template cast<ADScalar>())
+  , ad_data(ad_model)
+  {
+    ad_q = ADCongigVectorType(model.nq);
+    ad_q_plus = ADCongigVectorType(model.nq);
+    ad_dq = ADTangentVectorType(model.nv); ad_dq.setZero();
+    ad_v = ADTangentVectorType(model.nv); ad_v.setZero();
+    ad_a = ADTangentVectorType(model.nv); ad_a.setZero();
+    
+    ad_X = ADVectorXs(model.nv*3);
+    ad_Y = ADVectorXs(model.nv);
+  }
+  
+  void compute()
+  {
+    ad_X.head(ad_model.nv).setZero();
+    size_t abort_op_index = 0;
+    bool   record_compare = false;
+    CppAD::Independent(ad_X,abort_op_index,record_compare,ad_q);
+
+    Eigen::DenseIndex it = 0;
+    ad_dq = ad_X.head(ad_model.nv); it += ad_model.nv;
+    ad_v = ad_X.segment(it,ad_model.nv); it += ad_model.nv;
+    ad_a = ad_X.segment(it,ad_model.nv); it += ad_model.nv;
+    
+    ad_q_plus = se3::integrate(ad_model,ad_q,ad_dq);
+    se3::rnea(ad_model,ad_data,ad_q_plus,ad_v,ad_a);
+    
+    ad_Y = ad_data.tau;
+    
+    ad_fun.Dependent(ad_X,ad_Y);
+    ad_fun.optimize("no_compare_op");
+  }
+  
+  template<typename ConfigVectorType, typename TangentVector1, typename TangentVector2>
+  void eval(const Eigen::MatrixBase<ConfigVectorType> & q,
+            const Eigen::MatrixBase<TangentVector1> & v,
+            const Eigen::MatrixBase<TangentVector2> & a)
+  {
+    ad_fun.new_dynamic(q.derived());
+    
+    CPPAD_TESTVECTOR(EvalScalar) x((size_t)(ad_X.size()));
+    Eigen::DenseIndex it = 0;
+    Eigen::Map<typename Data::TangentVectorType>(x.data(),ad_model.nv,1).setZero();
+    it += ad_model.nv;
+    Eigen::Map<typename Data::TangentVectorType>(x.data()+it,ad_model.nv,1) = v;
+    it += ad_model.nv;
+    Eigen::Map<typename Data::TangentVectorType>(x.data()+it,ad_model.nv,1) = a;
+    it += ad_model.nv;
+    
+    CPPAD_TESTVECTOR(EvalScalar) dy_dx = ad_fun.Jacobian(x);
+    it = 0;
+    drnea_dq = Eigen::Map<typename EIGEN_PLAIN_ROW_MAJOR_TYPE(typename EvalData::MatrixXs)>(dy_dx.data(),ad_model.nv,ad_model.nv);
+    it += ad_model.nv * ad_model.nv;
+    drnea_dv = Eigen::Map<typename EIGEN_PLAIN_ROW_MAJOR_TYPE(typename EvalData::MatrixXs)>(dy_dx.data()+it,ad_model.nv,ad_model.nv);
+    it += ad_model.nv * ad_model.nv;
+    drnea_da = Eigen::Map<typename EIGEN_PLAIN_ROW_MAJOR_TYPE(typename EvalData::MatrixXs)>(dy_dx.data()+it,ad_model.nv,ad_model.nv);
+    it += ad_model.nv * ad_model.nv;
+  }
+  
+  // Results of eval
+  MatrixXs drnea_dq, drnea_dv, drnea_da;
+  ADCongigVectorType ad_q, ad_q_plus;
+  ADTangentVectorType ad_dq, ad_v, ad_a;
+  
+  ADVectorXs ad_X, ad_Y;
+  
+  ADFun ad_fun;
+  
+protected:
+  
+  ADModel ad_model;
+  ADData ad_data;
+};
+
+template<typename _Scalar>
+struct CodeGenRNEA : AutoDiffRNEA<CppAD::cg::CG<_Scalar>,_Scalar>
+{
+  typedef _Scalar Scalar;
+  typedef CppAD::cg::CG<Scalar> CGScalar;
+  typedef AutoDiffRNEA<CGScalar,Scalar> Base;
+  
+  typedef typename Base::ADScalar ADScalar;
+  typedef typename Base::EvalScalar EvalScalar;
+  
+  enum { Options = Base::Options };
+  
+  typedef se3::ModelTpl<Scalar,Options> Model;
+  
+  using Base::eval;
+  using Base::compute;
+  
+  CodeGenRNEA(const Model & model,
+              const std::string & function_name = "rnea",
+              const std::string & library_name = "cg_rnea")
+  : Base(model.template cast<ADScalar>())
+  , dynamicLib_ptr(nullptr)
+  {
+    compute();
+    
+    // generates source code
+    cgen_ptr = std::unique_ptr<CppAD::cg::ModelCSourceGen<Scalar> >(new CppAD::cg::ModelCSourceGen<Scalar>(Base::ad_fun, function_name));
+    cgen_ptr->setCreateJacobian(true);
+    cgen_ptr->setCreateForwardZero(true);
+//    cgen.setCreateForwardOne(true);
+//    cgen.setCreateReverseOne(true);
+//    cgen.setCreateReverseTwo(true);
+    libcgen_ptr = std::unique_ptr<CppAD::cg::ModelLibraryCSourceGen<Scalar> >(new CppAD::cg::ModelLibraryCSourceGen<Scalar>(*cgen_ptr));
+    
+    dynamicLibManager_ptr
+    = std::unique_ptr<CppAD::cg::DynamicModelLibraryProcessor<Scalar> >(new CppAD::cg::DynamicModelLibraryProcessor<Scalar>(*libcgen_ptr,library_name));
+  }
+  
+  bool existLib() const
+  {
+    const std::string filename = dynamicLibManager_ptr->getLibraryName() + CppAD::cg::system::SystemInfo<>::DYNAMIC_LIB_EXTENSION;
+    std::ifstream file(filename.c_str());
+    return file.good();
+  }
+  
+  void generateLib()
+  {
+    CppAD::cg::GccCompiler<Scalar> compiler;
+    dynamicLibManager_ptr->createDynamicLibrary(compiler,false);
+  }
+  
+  void loadLib(const bool generate_if_not_exist = true)
+  {
+    if(not existLib() && generate_if_not_exist)
+      generateLib();
+    
+    const auto it = dynamicLibManager_ptr->getOptions().find("dlOpenMode");
+    if (it == dynamicLibManager_ptr->getOptions().end())
+    {
+      dynamicLib_ptr.reset(new CppAD::cg::LinuxDynamicLib<Scalar>(dynamicLibManager_ptr->getLibraryName() +  CppAD::cg::system::SystemInfo<>::DYNAMIC_LIB_EXTENSION));
+    }
+    else
+    {
+      int dlOpenMode = std::stoi(it->second);
+      dynamicLib_ptr.reset(new CppAD::cg::LinuxDynamicLib<Scalar>(dynamicLibManager_ptr->getLibraryName() +  CppAD::cg::system::SystemInfo<>::DYNAMIC_LIB_EXTENSION, dlOpenMode));
+    }
+  }
+  
+protected:
+  
+  std::unique_ptr<CppAD::cg::ModelCSourceGen<Scalar> > cgen_ptr;
+  std::unique_ptr<CppAD::cg::ModelLibraryCSourceGen<Scalar> > libcgen_ptr;
+  std::unique_ptr<CppAD::cg::DynamicModelLibraryProcessor<Scalar> > dynamicLibManager_ptr;
+  std::unique_ptr<CppAD::cg::DynamicLib<Scalar> > dynamicLib_ptr;
+};
+
+template<typename Matrix1, typename Matrix2, typename Matrix3>
 void rnea_fd(const se3::Model & model, se3::Data & data_fd,
              const Eigen::VectorXd & q,
              const Eigen::VectorXd & v,
              const Eigen::VectorXd & a,
-             Eigen::MatrixXd & drnea_dq,
-             Eigen::MatrixXd & drnea_dv,
-             Eigen::MatrixXd & drnea_da)
+             const Eigen::MatrixBase<Matrix1> & _drnea_dq,
+             const Eigen::MatrixBase<Matrix2> & _drnea_dv,
+             const Eigen::MatrixBase<Matrix3> & _drnea_da)
 {
+  Matrix1 & drnea_dq = EIGEN_CONST_CAST(Matrix1,_drnea_dq);
+  Matrix2 & drnea_dv = EIGEN_CONST_CAST(Matrix2,_drnea_dv);
+  Matrix3 & drnea_da = EIGEN_CONST_CAST(Matrix3,_drnea_da);
+  
   using namespace Eigen;
   VectorXd v_eps(VectorXd::Zero(model.nv));
   VectorXd q_plus(model.nq);
@@ -77,8 +257,8 @@ void rnea_fd(const se3::Model & model, se3::Data & data_fd,
   
   // dRNEA/da
   drnea_da = crba(model,data_fd,q);
-  drnea_da.triangularView<Eigen::StrictlyLower>()
-  = drnea_da.transpose().triangularView<Eigen::StrictlyLower>();
+  drnea_da.template triangularView<Eigen::StrictlyLower>()
+  = drnea_da.transpose().template triangularView<Eigen::StrictlyLower>();
   
 }
 
@@ -88,7 +268,7 @@ void aba_fd(const se3::Model & model, se3::Data & data_fd,
             const Eigen::VectorXd & tau,
             Eigen::MatrixXd & daba_dq,
             Eigen::MatrixXd & daba_dv,
-            se3::Data::RowMatrixXd & daba_dtau)
+            se3::Data::RowMatrixXs & daba_dtau)
 {
   using namespace Eigen;
   VectorXd v_eps(VectorXd::Zero(model.nv));
@@ -157,6 +337,7 @@ int main(int argc, const char ** argv)
   else
     if(with_ff)
       se3::urdf::buildModel(filename,JointModelFreeFlyer(),model);
+//      se3::urdf::buildModel(filename,JointModelRX(),model);
     else
       se3::urdf::buildModel(filename,model);
   std::cout << "nq = " << model.nq << std::endl;
@@ -181,28 +362,34 @@ int main(int argc, const char ** argv)
     taus[i] = Eigen::VectorXd::Random(model.nv);
   }
 
-  MatrixXd drnea_dq(MatrixXd::Zero(model.nv,model.nv));
-  MatrixXd drnea_dv(MatrixXd::Zero(model.nv,model.nv));
+//  AutoDiffRNEA<double> ad_rnea(model);
+//  CodeGenRNEA<double> cg_rnea(model);
+//  cg_rnea.compute();
+//  cg_rnea.loadLib();
+  
+  EIGEN_PLAIN_ROW_MAJOR_TYPE(MatrixXd) drnea_dq(MatrixXd::Zero(model.nv,model.nv));
+  EIGEN_PLAIN_ROW_MAJOR_TYPE(MatrixXd) drnea_dv(MatrixXd::Zero(model.nv,model.nv));
+//  EIGEN_PLAIN_ROW_MAJOR_TYPE(MatrixXd)
   MatrixXd drnea_da(MatrixXd::Zero(model.nv,model.nv));
  
   MatrixXd daba_dq(MatrixXd::Zero(model.nv,model.nv));
   MatrixXd daba_dv(MatrixXd::Zero(model.nv,model.nv));
-  Data::RowMatrixXd daba_dtau(Data::RowMatrixXd::Zero(model.nv,model.nv));
-  
-  timer.tic();
-  SMOOTH(NBT)
-  {
-    forwardKinematics(model,data,qs[_smooth],qdots[_smooth],qddots[_smooth]);
-  }
-  std::cout << "FK= \t\t"; timer.toc(std::cout,NBT);
-  
-  timer.tic();
-  SMOOTH(NBT)
-  {
-    computeForwardKinematicsDerivatives(model,data,qs[_smooth],qdots[_smooth],qddots[_smooth]);
-  }
-  std::cout << "FK derivatives= \t\t"; timer.toc(std::cout,NBT);
+  Data::RowMatrixXs daba_dtau(Data::RowMatrixXs::Zero(model.nv,model.nv));
   
+//  timer.tic();
+//  SMOOTH(NBT)
+//  {
+//    forwardKinematics(model,data,qs[_smooth],qdots[_smooth],qddots[_smooth]);
+//  }
+//  std::cout << "FK= \t\t"; timer.toc(std::cout,NBT);
+//
+//  timer.tic();
+//  SMOOTH(NBT)
+//  {
+//    computeForwardKinematicsDerivatives(model,data,qs[_smooth],qdots[_smooth],qddots[_smooth]);
+//  }
+//  std::cout << "FK derivatives= \t\t"; timer.toc(std::cout,NBT);
+
   timer.tic();
   SMOOTH(NBT)
   {
@@ -218,14 +405,22 @@ int main(int argc, const char ** argv)
   }
   std::cout << "RNEA derivatives= \t\t"; timer.toc(std::cout,NBT);
   
+//  ad_rnea.compute();
+//  timer.tic();
+//  SMOOTH(NBT/100)
+//  {
+//    ad_rnea.eval(qs[_smooth],qdots[_smooth],qddots[_smooth]);
+//  }
+//  std::cout << "RNEA auto diff= \t\t"; timer.toc(std::cout,NBT/100);
+
   timer.tic();
-  SMOOTH(NBT)
+  SMOOTH(NBT/100)
   {
     rnea_fd(model,data,qs[_smooth],qdots[_smooth],qddots[_smooth],
             drnea_dq,drnea_dv,drnea_da);
   }
-  std::cout << "RNEA finite differences= \t\t"; timer.toc(std::cout,NBT);
-  
+  std::cout << "RNEA finite differences= \t\t"; timer.toc(std::cout,NBT/100);
+
   timer.tic();
   SMOOTH(NBT)
   {
@@ -248,23 +443,23 @@ int main(int argc, const char ** argv)
            daba_dq,daba_dv,daba_dtau);
   }
   std::cout << "ABA finite differences= \t\t"; timer.toc(std::cout,NBT);
-  
-  timer.tic();
-  SMOOTH(NBT)
-  {
-    computeMinverse(model,data,qs[_smooth]);
-  }
-  std::cout << "M.inverse() from ABA = \t\t"; timer.toc(std::cout,NBT);
-  
-  MatrixXd Minv(model.nv,model.nv); Minv.setZero();
-  timer.tic();
-  SMOOTH(NBT)
-  {
-    crba(model,data,qs[_smooth]);
-    cholesky::decompose(model,data);
-    cholesky::computeMinv(model,data,Minv);
-  }
-  std::cout << "Minv from Cholesky = \t\t"; timer.toc(std::cout,NBT);
+//
+//  timer.tic();
+//  SMOOTH(NBT)
+//  {
+//    computeMinverse(model,data,qs[_smooth]);
+//  }
+//  std::cout << "M.inverse() from ABA = \t\t"; timer.toc(std::cout,NBT);
+//  
+//  MatrixXd Minv(model.nv,model.nv); Minv.setZero();
+//  timer.tic();
+//  SMOOTH(NBT)
+//  {
+//    crba(model,data,qs[_smooth]);
+//    cholesky::decompose(model,data);
+//    cholesky::computeMinv(model,data,Minv);
+//  }
+//  std::cout << "Minv from Cholesky = \t\t"; timer.toc(std::cout,NBT);
 
   std::cout << "--" << std::endl;
   return 0;