diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9e86d1c45ca36f882fc83d1df779ed0bf85c9818..d692db2400cc152bb0fa45e6308dd99560a57d97 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -135,6 +135,7 @@ SET(${PROJECT_NAME}_ALGORITHM_HEADERS
   algorithm/jacobian.hpp
   algorithm/jacobian.hxx
   algorithm/cholesky.hpp
+  algorithm/cholesky.hxx
   algorithm/kinematics.hpp
   algorithm/center-of-mass.hpp
   algorithm/center-of-mass.hxx
diff --git a/src/algorithm/cholesky.hpp b/src/algorithm/cholesky.hpp
index f1fc4dce73f3b6798924dda7b847ff6050dd8dae..7fce3ed23f68f23034b199587fe7fec1330eaa18 100644
--- a/src/algorithm/cholesky.hpp
+++ b/src/algorithm/cholesky.hpp
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2015 CNRS
+// Copyright (c) 2015-2016 CNRS
 //
 // This file is part of Pinocchio
 // Pinocchio is free software: you can redistribute it
@@ -27,207 +27,47 @@ namespace se3
 {
   namespace cholesky
   {
-    inline const Eigen::MatrixXd&
-    decompose(const Model & model, 
-	      Data&         data );
 
     template<typename Mat>
-    Mat & solve( const Model &            model, 
-		 const Data&              data ,
-		 Eigen::MatrixBase<Mat> & v);
+    Mat & solve(const Model & model, const Data & data,
+                Eigen::MatrixBase<Mat> & v);
 
     template<typename Mat>
-    Mat & Mv( const Model &              model, 
-	      const  Data&               data ,
-	      Eigen::MatrixBase<Mat> &   v,
-	      bool usingCholesky = false);
-
-  } // namespace cholesky  
-} // namespace se3 
-
-/* --- Details -------------------------------------------------------------------- */
-
-namespace se3 
-{
-  namespace cholesky
-  {
-
-    inline const Eigen::MatrixXd&
-    decompose(const Model &           model, 
-	      Data&                   data )
-    {
-      /*  
-       *    D = zeros(n,1);
-       *    U = eye(n);
-       *    for j=n:-1:1
-       *      subtree = j+1:tree(j);
-       *      D(j) = M(j,j) - U(j,subtree)*diag(D(subtree))*U(j,subtree)';
-       *      i=parent(j);
-       *      while i>0
-       *          U(i,j) = (M(i,j) - U(i,subtree)*diag(D(subtree))*U(j,subtree)') / D(j);
-       *          i=parent(i);
-       *      end
-       *    end
-       */
-
-      Eigen::MatrixXd & M = data.M;
-      Eigen::MatrixXd & U = data.U;
-      Eigen::VectorXd & D = data.D;
-
-      for(int j=model.nv-1;j>=0;--j )
-	{
-	  const int NVT = data.nvSubtree_fromRow[(Model::Index)j]-1;
-	  Eigen::VectorXd::SegmentReturnType DUt = data.tmp.head(NVT);
-	  if(NVT)
-	    DUt = U.row(j).segment(j+1,NVT).transpose()
-	      .cwiseProduct(D.segment(j+1,NVT));
-	
-	  D[j] = M(j,j) - U.row(j).segment(j+1,NVT) * DUt;
-	
-	  for( int _i=data.parents_fromRow[(Model::Index)j];_i>=0;_i=data.parents_fromRow[(Model::Index)_i] )
-	    U(_i,j) = (M(_i,j) - U.row(_i).segment(j+1,NVT).dot(DUt)) / D[j]; 
-	}
-
-      return data.U;
-    }
-
-    /* Compute U*v.
-     * Nota: there is no smart way of doing U*D*v, so it is not proposed. */
+    Mat & Mv( const Model & model, const Data & data ,
+             Eigen::MatrixBase<Mat> & v,
+             const bool usingCholesky = false);
+    
     template<typename Mat>
-    Mat & 
-    Uv( const Model &                  model, 
-	const Data&                    data ,
-	Eigen::MatrixBase<Mat> &   v)
-    {
-      assert(v.size() == model.nv);
-      EIGEN_STATIC_ASSERT_VECTOR_ONLY(Mat);
-      const Eigen::MatrixXd & U = data.U;
-      const std::vector<int> & nvt = data.nvSubtree_fromRow;
-
-      for( int k=0;k<model.nv-1;++k ) // You can stop one step before nv
-	v[k] += U.row(k).segment(k+1,nvt[(Model::Index)k]-1) * v.segment(k+1,nvt[(Model::Index)k]-1);
-
-      return v.derived();
-    }
-
-    /* Compute U'*v */
+    Mat & Uv(const Model & model,
+             const Data & data,
+             Eigen::MatrixBase<Mat> & v);
+    
     template<typename Mat>
-    Mat &
-    Utv( const Model &                  model, 
-	 const Data&                          data ,
-	 Eigen::MatrixBase<Mat> &   v)
-    {
-      assert(v.size() == model.nv);
-      EIGEN_STATIC_ASSERT_VECTOR_ONLY(Mat);
-
-      const Eigen::MatrixXd & U = data.U;
-      const std::vector<int> & nvt = data.nvSubtree_fromRow;
-      for( int i=model.nv-2;i>=0;--i ) // You can start from nv-2 (no child in nv-1)
-	v.segment(i+1,nvt[(Model::Index)i]-1) += U.row(i).segment(i+1,nvt[(Model::Index)i]-1).transpose()*v[i];
-      
-      return v.derived();
-    }
-  
-    /* Compute U^{-1}*v 
-     * Nota: there is no efficient way to compute D^{-1}U^{-1}v
-     * in a single loop, so algorithm is not proposed.*/
+    Mat & Utv(const Model & model,
+              const Data & data,
+              Eigen::MatrixBase<Mat> & v);
+    
     template<typename Mat>
-    Mat &
-    Uiv( const Model &                  model, 
-	 const Data&                          data ,
-	 Eigen::MatrixBase<Mat> &   v)
-    {
-      /* We search y s.t. v = U y. 
-       * For any k, v_k = y_k + U_{k,k+1:} y_{k+1:} */
-      assert(v.size() == model.nv);
-      EIGEN_STATIC_ASSERT_VECTOR_ONLY(Mat);
-
-      const Eigen::MatrixXd & U = data.U;
-      const std::vector<int> & nvt = data.nvSubtree_fromRow;
-
-      for( int k=model.nv-2;k>=0;--k ) // You can start from nv-2 (no child in nv-1)
-	v[k] -= U.row(k).segment(k+1,nvt[(Model::Index)k]-1) * v.segment(k+1,nvt[(Model::Index)k]-1);
-      return v.derived();
-    }
-
-    template<typename Mat>
-    Mat &
-    Utiv( const Model &                  model, 
-	  const  Data&                          data ,
-	  Eigen::MatrixBase<Mat> &   v)
-    {
-      /* We search y s.t. v = U' y. 
-       * For any k, v_k = y_k + sum_{m \in parent{k}} U(m,k) v(k). */
-
-      assert(v.size() == model.nv);
-      EIGEN_STATIC_ASSERT_VECTOR_ONLY(Mat);
-      
-      const Eigen::MatrixXd & U = data.U;
-      const std::vector<int> & nvt = data.nvSubtree_fromRow;
-      for( int i=0;i<model.nv-1;++i ) // You can stop one step before nv.
-	v.segment(i+1,nvt[(Model::Index)i]-1) -= U.row(i).segment(i+1,nvt[(Model::Index)i]-1).transpose()*v[i];
-
-      return v.derived();
-    }
-
-    namespace internal
-    {
-      template<typename Mat>
-      Mat
-      Mv( const Model &                  model, 
-	  const  Data&                          data ,
-	  const Eigen::MatrixBase<Mat> &   v)
-      {
-	assert(v.size() == model.nv);
-	EIGEN_STATIC_ASSERT_VECTOR_ONLY(Mat);
-      
-	const Eigen::MatrixXd & M = data.M;
-	const std::vector<int> & nvt = data.nvSubtree_fromRow;
-	Mat res(model.nv);
-
-	for( int k=model.nv-1;k>=0;--k ) 
-	  {
-	    res[k] = M.row(k).segment(k,nvt[(Model::Index)k]) * v.segment(k,nvt[(Model::Index)k]);
-	    res.segment(k+1,nvt[(Model::Index)k]-1) += M.row(k).segment(k+1,nvt[(Model::Index)k]-1).transpose()*v[k];
-	  }
-
-	return res;
-      }
-
-      template<typename Mat>
-      Mat &
-      UDUtv( const Model &              model, 
-	     const Data&                data ,
-	     Eigen::MatrixBase<Mat> &   v)
-      {
-	Utv(model,data,v);
-	for( int k=0;k<model.nv;++k ) v[k] *= data.D[k];
-	return Uv(model,data,v);
-      }
-    } // internal
-  
+    Mat & Uiv(const Model & model,
+              const Data & data ,
+              Eigen::MatrixBase<Mat> & v);
+    
     template<typename Mat>
-    Mat &
-    Mv( const Model &                  model, 
-	const  Data&                          data ,
-	Eigen::MatrixBase<Mat> &   v,
-	bool usingCholesky)
-    {
-      if(usingCholesky) return internal::UDUtv(model,data,v);
-      else return v = internal::Mv(model,data,v);
-    }
-
+    Mat & Utiv(const Model & model,
+               const Data & data ,
+               Eigen::MatrixBase<Mat> & v);
+    
     template<typename Mat>
-    Mat &
-    solve( const Model &              model, 
-	   const Data&                data ,
-	   Eigen::MatrixBase<Mat> &   v)
-    {
-      Uiv(model,data,v);
-      for( int k=0;k<model.nv;++k ) v[k] /= data.D[k];
-      return Utiv(model,data,v);
-    }
+    Mat & solve(const Model & model,
+                const Data & data ,
+                Eigen::MatrixBase<Mat> & v);
 
-  } //   namespace cholesky
+  } // namespace cholesky  
 } // namespace se3 
+
+/* --- Details -------------------------------------------------------------------- */
+/* --- Details -------------------------------------------------------------------- */
+/* --- Details -------------------------------------------------------------------- */
+#include "pinocchio/algorithm/cholesky.hxx"
+
 #endif // ifndef __se3_cholesky_hpp__
diff --git a/src/algorithm/cholesky.hxx b/src/algorithm/cholesky.hxx
new file mode 100644
index 0000000000000000000000000000000000000000..ecc483d0eab69623152ba3cf6a71de15875ba051
--- /dev/null
+++ b/src/algorithm/cholesky.hxx
@@ -0,0 +1,196 @@
+//
+// Copyright (c) 2015-2016 CNRS
+//
+// This file is part of Pinocchio
+// Pinocchio is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation, either version
+// 3 of the License, or (at your option) any later version.
+//
+// Pinocchio is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Lesser Public License for more details. You should have
+// received a copy of the GNU Lesser General Public License along with
+// Pinocchio If not, see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef __se3_cholesky_hxx__
+#define __se3_cholesky_hxx__
+
+namespace se3 
+{
+  namespace cholesky
+  {
+
+    inline const Eigen::MatrixXd &
+    decompose(const Model & model,
+              Data & data)
+    {
+      /*
+       *    D = zeros(n,1);
+       *    U = eye(n);
+       *    for j=n:-1:1
+       *      subtree = j+1:tree(j);
+       *      D(j) = M(j,j) - U(j,subtree)*diag(D(subtree))*U(j,subtree)';
+       *      i=parent(j);
+       *      while i>0
+       *          U(i,j) = (M(i,j) - U(i,subtree)*diag(D(subtree))*U(j,subtree)') / D(j);
+       *          i=parent(i);
+       *      end
+       *    end
+       */
+      
+      Eigen::MatrixXd & M = data.M;
+      Eigen::MatrixXd & U = data.U;
+      Eigen::VectorXd & D = data.D;
+      
+      for(int j=model.nv-1;j>=0;--j )
+      {
+        const int NVT = data.nvSubtree_fromRow[(Model::Index)j]-1;
+        Eigen::VectorXd::SegmentReturnType DUt = data.tmp.head(NVT);
+        if(NVT)
+          DUt = U.row(j).segment(j+1,NVT).transpose()
+          .cwiseProduct(D.segment(j+1,NVT));
+        
+        D[j] = M(j,j) - U.row(j).segment(j+1,NVT) * DUt;
+        
+        for(int _i = data.parents_fromRow[(Model::Index)j];_i >= 0;_i = data.parents_fromRow[(Model::Index)_i])
+          U(_i,j) = (M(_i,j) - U.row(_i).segment(j+1,NVT).dot(DUt)) / D[j];
+      }
+      
+      return data.U;
+    }
+
+    /* Compute U*v.
+     * Nota: there is no smart way of doing U*D*v, so it is not proposed. */
+    template<typename Mat>
+    Mat & Uv(const Model & model,
+             const Data & data,
+             Eigen::MatrixBase<Mat> & v)
+    {
+      assert(v.size() == model.nv);
+      EIGEN_STATIC_ASSERT_VECTOR_ONLY(Mat);
+      const Eigen::MatrixXd & U = data.U;
+      const std::vector<int> & nvt = data.nvSubtree_fromRow;
+      
+      for(int k=0;k < model.nv-1;++k) // You can stop one step before nv
+        v[k] += U.row(k).segment(k+1,nvt[(Model::Index)k]-1) * v.segment(k+1,nvt[(Model::Index)k]-1);
+      
+      return v.derived();
+    }
+
+    /* Compute U'*v */
+    template<typename Mat>
+    Mat & Utv(const Model & model,
+              const Data & data,
+              Eigen::MatrixBase<Mat> & v)
+    {
+      assert(v.size() == model.nv);
+      EIGEN_STATIC_ASSERT_VECTOR_ONLY(Mat);
+      
+      const Eigen::MatrixXd & U = data.U;
+      const std::vector<int> & nvt = data.nvSubtree_fromRow;
+      for( int i=model.nv-2;i>=0;--i ) // You can start from nv-2 (no child in nv-1)
+        v.segment(i+1,nvt[(Model::Index)i]-1) += U.row(i).segment(i+1,nvt[(Model::Index)i]-1).transpose()*v[i];
+      
+      return v.derived();
+    }
+  
+    /* Compute U^{-1}*v 
+     * Nota: there is no efficient way to compute D^{-1}U^{-1}v
+     * in a single loop, so algorithm is not proposed.*/
+    template<typename Mat>
+    Mat & Uiv(const Model & model,
+              const Data & data ,
+              Eigen::MatrixBase<Mat> & v)
+    {
+      /* We search y s.t. v = U y. 
+       * For any k, v_k = y_k + U_{k,k+1:} y_{k+1:} */
+      assert(v.size() == model.nv);
+      EIGEN_STATIC_ASSERT_VECTOR_ONLY(Mat);
+      
+      const Eigen::MatrixXd & U = data.U;
+      const std::vector<int> & nvt = data.nvSubtree_fromRow;
+      
+      for( int k=model.nv-2;k>=0;--k ) // You can start from nv-2 (no child in nv-1)
+        v[k] -= U.row(k).segment(k+1,nvt[(Model::Index)k]-1) * v.segment(k+1,nvt[(Model::Index)k]-1);
+      return v.derived();
+    }
+
+    template<typename Mat>
+    Mat & Utiv(const Model & model,
+               const Data & data ,
+               Eigen::MatrixBase<Mat> & v)
+    {
+      /* We search y s.t. v = U' y. 
+       * For any k, v_k = y_k + sum_{m \in parent{k}} U(m,k) v(k). */
+      assert(v.size() == model.nv);
+      EIGEN_STATIC_ASSERT_VECTOR_ONLY(Mat);
+      
+      const Eigen::MatrixXd & U = data.U;
+      const std::vector<int> & nvt = data.nvSubtree_fromRow;
+      for( int i=0;i<model.nv-1;++i ) // You can stop one step before nv.
+        v.segment(i+1,nvt[(Model::Index)i]-1) -= U.row(i).segment(i+1,nvt[(Model::Index)i]-1).transpose()*v[i];
+
+      return v.derived();
+    }
+
+    namespace internal
+    {
+      template<typename Mat>
+      Mat Mv(const Model & model,
+             const Data & data,
+             const Eigen::MatrixBase<Mat> & v)
+      {
+        assert(v.size() == model.nv);
+        EIGEN_STATIC_ASSERT_VECTOR_ONLY(Mat);
+        
+        const Eigen::MatrixXd & M = data.M;
+        const std::vector<int> & nvt = data.nvSubtree_fromRow;
+        Mat res(model.nv);
+        
+        for(int k=model.nv-1;k>=0;--k)
+        {
+          res[k] = M.row(k).segment(k,nvt[(Model::Index)k]) * v.segment(k,nvt[(Model::Index)k]);
+          res.segment(k+1,nvt[(Model::Index)k]-1) += M.row(k).segment(k+1,nvt[(Model::Index)k]-1).transpose()*v[k];
+        }
+        
+        return res;
+      }
+      
+      template<typename Mat>
+      Mat & UDUtv(const Model & model,
+                  const Data & data,
+                  Eigen::MatrixBase<Mat> & v)
+      {
+        Utv(model,data,v);
+        for( int k=0;k<model.nv;++k ) v[k] *= data.D[k];
+        return Uv(model,data,v);
+      }
+    } // internal
+    
+    template<typename Mat>
+    Mat & Mv(const Model & model,
+             const Data & data,
+             Eigen::MatrixBase<Mat> & v,
+             const bool usingCholesky)
+    {
+      if(usingCholesky) return internal::UDUtv(model,data,v);
+      else return v = internal::Mv(model,data,v);
+    }
+    
+    template<typename Mat>
+    Mat & solve(const Model & model,
+                const Data & data ,
+                Eigen::MatrixBase<Mat> & v)
+    {
+      Uiv(model,data,v);
+      for(int k=0;k<model.nv;++k) v[k] /= data.D[k];
+      return Utiv(model,data,v);
+    }
+
+  } //   namespace cholesky
+} // namespace se3
+
+#endif // ifndef __se3_cholesky_hxx__