diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index db03ba20fa09c0cfc1b946c9d76eaab4015a230c..2367b92de25c00e59e30cb44db384a8af12ae3bc 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -163,8 +163,8 @@ ENDIF(YAMLCPP_FOUND)
 SET(HDRS_BASE
     capture_base.h
     constraint_analytic.h
+    constraint_autodiff.h
     constraint_base.h
-    constraint_sparse.h
     factory.h
     feature_base.h
     feature_match.h
@@ -207,6 +207,7 @@ SET(HDRS
     capture_void.h
     constraint_container.h
     constraint_corner_2D.h
+    constraint_AHP.h
     constraint_epipolar.h
     constraint_imu.h
     constraint_fix.h
@@ -326,20 +327,18 @@ SET(SRCS_DTASSC
 #optional HDRS and SRCS
 IF (Ceres_FOUND)
     SET(HDRS_WRAPPER
-        ceres_wrapper/auto_diff_cost_function_wrapper.h
+        ceres_wrapper/sparse_utils.h
+        ceres_wrapper/solver_manager.h
         ceres_wrapper/ceres_manager.h
+        #ceres_wrapper/qr_manager.h
         ceres_wrapper/cost_function_wrapper.h
-        ceres_wrapper/create_auto_diff_cost_function.h
-        ceres_wrapper/create_auto_diff_cost_function_ceres.h
-        ceres_wrapper/create_auto_diff_cost_function_wrapper.h
         ceres_wrapper/create_numeric_diff_cost_function.h
-        ceres_wrapper/create_numeric_diff_cost_function_ceres.h
         ceres_wrapper/local_parametrization_wrapper.h 
         )
     SET(SRCS_WRAPPER
+        ceres_wrapper/solver_manager.cpp
         ceres_wrapper/ceres_manager.cpp
-        ceres_wrapper/create_auto_diff_cost_function.cpp
-        ceres_wrapper/create_numeric_diff_cost_function.cpp
+        #ceres_wrapper/qr_manager.cpp
         ceres_wrapper/local_parametrization_wrapper.cpp 
         )
 ELSE(Ceres_FOUND)
@@ -424,7 +423,7 @@ IF(YAMLCPP_FOUND)
     ENDIF(laser_scan_utils_FOUND)
     IF(OpenCV_FOUND)
         SET(SRCS ${SRCS}
-            yaml/processor_image_yaml.cpp
+        	yaml/processor_image_yaml.cpp
             )
     ENDIF(OpenCV_FOUND)
 ENDIF(YAMLCPP_FOUND)
diff --git a/src/ceres_wrapper/auto_diff_cost_function_wrapper.h b/src/ceres_wrapper/auto_diff_cost_function_wrapper.h
deleted file mode 100644
index ba5362ded5b1e7eb39bec9603dfa0db08e8c9fe9..0000000000000000000000000000000000000000
--- a/src/ceres_wrapper/auto_diff_cost_function_wrapper.h
+++ /dev/null
@@ -1,1176 +0,0 @@
-#ifndef TRUNK_SRC_AUTODIFF_COST_FUNCTION_WRAPPER_H_
-#define TRUNK_SRC_AUTODIFF_COST_FUNCTION_WRAPPER_H_
-
-// WOLF
-#include "../wolf.h"
-
-// CERES
-#include "ceres/jet.h"
-#include "ceres/sized_cost_function.h"
-
-// GENERAL
-#include <array>
-
-namespace wolf {
-
-template <class ConstraintType, const unsigned int MEASUREMENT_SIZE,
-          unsigned int BLOCK_0_SIZE, unsigned int BLOCK_1_SIZE, unsigned int BLOCK_2_SIZE, unsigned int BLOCK_3_SIZE, unsigned int BLOCK_4_SIZE,
-          unsigned int BLOCK_5_SIZE, unsigned int BLOCK_6_SIZE, unsigned int BLOCK_7_SIZE, unsigned int BLOCK_8_SIZE, unsigned int BLOCK_9_SIZE>
-class AutoDiffCostFunctionWrapperBase : public ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                                                             BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,
-                                                             BLOCK_5_SIZE,BLOCK_6_SIZE,BLOCK_7_SIZE,BLOCK_8_SIZE,BLOCK_9_SIZE>
-{
-    typedef ceres::Jet<Scalar, BLOCK_0_SIZE + BLOCK_1_SIZE + BLOCK_2_SIZE + BLOCK_3_SIZE + BLOCK_4_SIZE +
-                                   BLOCK_5_SIZE + BLOCK_6_SIZE + BLOCK_7_SIZE + BLOCK_8_SIZE + BLOCK_9_SIZE> WolfJet;
-
-    protected:
-        ConstraintType* constraint_ptr_;
-        unsigned int n_blocks_;
-        std::vector<unsigned int> block_sizes_, jacobian_locations_;
-        std::array<WolfJet, BLOCK_0_SIZE>* jets_0_;
-        std::array<WolfJet, BLOCK_1_SIZE>* jets_1_;
-        std::array<WolfJet, BLOCK_2_SIZE>* jets_2_;
-        std::array<WolfJet, BLOCK_3_SIZE>* jets_3_;
-        std::array<WolfJet, BLOCK_4_SIZE>* jets_4_;
-        std::array<WolfJet, BLOCK_5_SIZE>* jets_5_;
-        std::array<WolfJet, BLOCK_6_SIZE>* jets_6_;
-        std::array<WolfJet, BLOCK_7_SIZE>* jets_7_;
-        std::array<WolfJet, BLOCK_8_SIZE>* jets_8_;
-        std::array<WolfJet, BLOCK_9_SIZE>* jets_9_;
-        std::array<WolfJet, MEASUREMENT_SIZE>* residuals_jets_;
-
-    public:
-
-        AutoDiffCostFunctionWrapperBase(ConstraintType* _constraint_ptr) :
-            ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                                     BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,
-                                     BLOCK_5_SIZE,BLOCK_6_SIZE,BLOCK_7_SIZE,BLOCK_8_SIZE,BLOCK_9_SIZE>(),
-            constraint_ptr_(_constraint_ptr),
-            n_blocks_(10),
-            block_sizes_({BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, BLOCK_3_SIZE, BLOCK_4_SIZE,
-                          BLOCK_5_SIZE, BLOCK_6_SIZE, BLOCK_7_SIZE, BLOCK_8_SIZE, BLOCK_9_SIZE}),
-            jacobian_locations_({0,
-                                 BLOCK_0_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE+BLOCK_5_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE+BLOCK_5_SIZE+BLOCK_6_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE+BLOCK_5_SIZE+BLOCK_6_SIZE+BLOCK_7_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE+BLOCK_5_SIZE+BLOCK_6_SIZE+BLOCK_7_SIZE+BLOCK_8_SIZE}),
-            jets_0_(new std::array<WolfJet, BLOCK_0_SIZE>),
-            jets_1_(new std::array<WolfJet, BLOCK_1_SIZE>),
-            jets_2_(new std::array<WolfJet, BLOCK_2_SIZE>),
-            jets_3_(new std::array<WolfJet, BLOCK_3_SIZE>),
-            jets_4_(new std::array<WolfJet, BLOCK_4_SIZE>),
-            jets_5_(new std::array<WolfJet, BLOCK_5_SIZE>),
-            jets_6_(new std::array<WolfJet, BLOCK_6_SIZE>),
-            jets_7_(new std::array<WolfJet, BLOCK_7_SIZE>),
-            jets_8_(new std::array<WolfJet, BLOCK_8_SIZE>),
-            jets_9_(new std::array<WolfJet, BLOCK_9_SIZE>),
-            residuals_jets_(new std::array<WolfJet, MEASUREMENT_SIZE>)
-        {
-            // initialize jets
-            unsigned int i, last_jet_idx = 0;
-            for (i = 0; i < BLOCK_0_SIZE; i++)
-                (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_1_SIZE; i++)
-                (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_2_SIZE; i++)
-                (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_3_SIZE; i++)
-                (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_4_SIZE; i++)
-                (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_5_SIZE; i++)
-                (*jets_5_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_6_SIZE; i++)
-                (*jets_6_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_7_SIZE; i++)
-                (*jets_7_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_8_SIZE; i++)
-                (*jets_8_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_9_SIZE; i++)
-                (*jets_9_)[i] = WolfJet(0, last_jet_idx++);
-
-        };
-
-        virtual ~AutoDiffCostFunctionWrapperBase()
-        {
-            delete jets_0_;
-            delete jets_1_;
-            delete jets_2_;
-            delete jets_3_;
-            delete jets_4_;
-            delete jets_5_;
-            delete jets_6_;
-            delete jets_7_;
-            delete jets_8_;
-            delete jets_9_;
-            delete residuals_jets_;
-        };
-
-        virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
-        {
-            // only residuals
-            if (jacobians == nullptr)
-            {
-                (*this->constraint_ptr_)(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4],
-                                         parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], residuals);
-            }
-            // also compute jacobians
-            else
-            {
-                // update jets real part
-                unsigned int i;
-                for (i = 0; i < BLOCK_0_SIZE; i++)
-                    (*jets_0_)[i].a = parameters[0][i];
-                for (i = 0; i < BLOCK_1_SIZE; i++)
-                    (*jets_1_)[i].a = parameters[1][i];
-                for (i = 0; i < BLOCK_2_SIZE; i++)
-                    (*jets_2_)[i].a = parameters[2][i];
-                for (i = 0; i < BLOCK_3_SIZE; i++)
-                    (*jets_3_)[i].a = parameters[3][i];
-                for (i = 0; i < BLOCK_4_SIZE; i++)
-                    (*jets_4_)[i].a = parameters[4][i];
-                for (i = 0; i < BLOCK_5_SIZE; i++)
-                    (*jets_5_)[i].a = parameters[5][i];
-                for (i = 0; i < BLOCK_6_SIZE; i++)
-                    (*jets_6_)[i].a = parameters[6][i];
-                for (i = 0; i < BLOCK_7_SIZE; i++)
-                    (*jets_7_)[i].a = parameters[7][i];
-                for (i = 0; i < BLOCK_8_SIZE; i++)
-                    (*jets_8_)[i].a = parameters[8][i];
-                for (i = 0; i < BLOCK_9_SIZE; i++)
-                    (*jets_9_)[i].a = parameters[9][i];
-
-                // call functor
-                (*this->constraint_ptr_)(jets_0_->data(), jets_1_->data(), jets_2_->data(), jets_3_->data(), jets_4_->data(),
-                                         jets_5_->data(), jets_6_->data(), jets_7_->data(), jets_8_->data(), jets_9_->data(),
-                                         residuals_jets_->data());
-
-                // fill the residual array
-                for (i = 0; i < MEASUREMENT_SIZE; i++)
-                    residuals[i] = (*residuals_jets_)[i].a;
-
-                // fill the jacobian matrices
-                for (i = 0; i<this->n_blocks_; i++)
-                    if (jacobians[i] != nullptr)
-                        for (unsigned int row = 0; row < MEASUREMENT_SIZE; row++)
-                            std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
-                                      (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + block_sizes_.at(i),
-                                      jacobians[i] + row * block_sizes_.at(i));
-            }
-            return true;
-        }
-};
-
-// SPECIALIZATION 9 BLOCKS
-template <class ConstraintType, const unsigned int MEASUREMENT_SIZE,
-          unsigned int BLOCK_0_SIZE, unsigned int BLOCK_1_SIZE, unsigned int BLOCK_2_SIZE, unsigned int BLOCK_3_SIZE, unsigned int BLOCK_4_SIZE,
-          unsigned int BLOCK_5_SIZE, unsigned int BLOCK_6_SIZE, unsigned int BLOCK_7_SIZE, unsigned int BLOCK_8_SIZE>
-class AutoDiffCostFunctionWrapperBase<ConstraintType, MEASUREMENT_SIZE,
-                                  BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, BLOCK_3_SIZE, BLOCK_4_SIZE,
-                                  BLOCK_5_SIZE, BLOCK_6_SIZE, BLOCK_7_SIZE, BLOCK_8_SIZE, 0>
-    : public ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                               BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,
-                               BLOCK_5_SIZE,BLOCK_6_SIZE,BLOCK_7_SIZE,BLOCK_8_SIZE,0>
-{
-    typedef ceres::Jet<Scalar, BLOCK_0_SIZE + BLOCK_1_SIZE + BLOCK_2_SIZE + BLOCK_3_SIZE + BLOCK_4_SIZE +
-                                   BLOCK_5_SIZE + BLOCK_6_SIZE + BLOCK_7_SIZE + BLOCK_8_SIZE> WolfJet;
-
-    protected:
-        ConstraintType* constraint_ptr_;
-        unsigned int n_blocks_;
-        std::vector<unsigned int> block_sizes_, jacobian_locations_;
-        std::array<WolfJet, BLOCK_0_SIZE>* jets_0_;
-        std::array<WolfJet, BLOCK_1_SIZE>* jets_1_;
-        std::array<WolfJet, BLOCK_2_SIZE>* jets_2_;
-        std::array<WolfJet, BLOCK_3_SIZE>* jets_3_;
-        std::array<WolfJet, BLOCK_4_SIZE>* jets_4_;
-        std::array<WolfJet, BLOCK_5_SIZE>* jets_5_;
-        std::array<WolfJet, BLOCK_6_SIZE>* jets_6_;
-        std::array<WolfJet, BLOCK_7_SIZE>* jets_7_;
-        std::array<WolfJet, BLOCK_8_SIZE>* jets_8_;
-        std::array<WolfJet, MEASUREMENT_SIZE>* residuals_jets_;
-
-    public:
-
-        AutoDiffCostFunctionWrapperBase(ConstraintType* _constraint_ptr) :
-            ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                                     BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,
-                                     BLOCK_5_SIZE,BLOCK_6_SIZE,BLOCK_7_SIZE,BLOCK_8_SIZE,0>(),
-            constraint_ptr_(_constraint_ptr),
-            n_blocks_(9),
-            block_sizes_({BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, BLOCK_3_SIZE, BLOCK_4_SIZE,
-                          BLOCK_5_SIZE, BLOCK_6_SIZE, BLOCK_7_SIZE, BLOCK_8_SIZE}),
-            jacobian_locations_({0,
-                                 BLOCK_0_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE+BLOCK_5_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE+BLOCK_5_SIZE+BLOCK_6_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE+BLOCK_5_SIZE+BLOCK_6_SIZE+BLOCK_7_SIZE}),
-            jets_0_(new std::array<WolfJet, BLOCK_0_SIZE>),
-            jets_1_(new std::array<WolfJet, BLOCK_1_SIZE>),
-            jets_2_(new std::array<WolfJet, BLOCK_2_SIZE>),
-            jets_3_(new std::array<WolfJet, BLOCK_3_SIZE>),
-            jets_4_(new std::array<WolfJet, BLOCK_4_SIZE>),
-            jets_5_(new std::array<WolfJet, BLOCK_5_SIZE>),
-            jets_6_(new std::array<WolfJet, BLOCK_6_SIZE>),
-            jets_7_(new std::array<WolfJet, BLOCK_7_SIZE>),
-            jets_8_(new std::array<WolfJet, BLOCK_8_SIZE>),
-            residuals_jets_(new std::array<WolfJet, MEASUREMENT_SIZE>)
-        {
-            // initialize jets
-            unsigned int i, last_jet_idx = 0;
-            for (i = 0; i < BLOCK_0_SIZE; i++)
-                (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_1_SIZE; i++)
-                (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_2_SIZE; i++)
-                (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_3_SIZE; i++)
-                (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_4_SIZE; i++)
-                (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_5_SIZE; i++)
-                (*jets_5_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_6_SIZE; i++)
-                (*jets_6_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_7_SIZE; i++)
-                (*jets_7_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_8_SIZE; i++)
-                (*jets_8_)[i] = WolfJet(0, last_jet_idx++);
-        };
-
-        virtual ~AutoDiffCostFunctionWrapperBase()
-        {
-            delete jets_0_;
-            delete jets_1_;
-            delete jets_2_;
-            delete jets_3_;
-            delete jets_4_;
-            delete jets_5_;
-            delete jets_6_;
-            delete jets_7_;
-            delete jets_8_;
-            delete residuals_jets_;
-        };
-
-        virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
-        {
-            // only residuals
-            if (jacobians == nullptr)
-                (*this->constraint_ptr_)(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4],
-                                         parameters[5], parameters[6], parameters[7], parameters[8], residuals);
-
-            // also compute jacobians
-            else
-            {
-                // update jets real part
-                unsigned int i;
-                for (i = 0; i < BLOCK_0_SIZE; i++)
-                    (*jets_0_)[i].a = parameters[0][i];
-                for (i = 0; i < BLOCK_1_SIZE; i++)
-                    (*jets_1_)[i].a = parameters[1][i];
-                for (i = 0; i < BLOCK_2_SIZE; i++)
-                    (*jets_2_)[i].a = parameters[2][i];
-                for (i = 0; i < BLOCK_3_SIZE; i++)
-                    (*jets_3_)[i].a = parameters[3][i];
-                for (i = 0; i < BLOCK_4_SIZE; i++)
-                    (*jets_4_)[i].a = parameters[4][i];
-                for (i = 0; i < BLOCK_5_SIZE; i++)
-                    (*jets_5_)[i].a = parameters[5][i];
-                for (i = 0; i < BLOCK_6_SIZE; i++)
-                    (*jets_6_)[i].a = parameters[6][i];
-                for (i = 0; i < BLOCK_7_SIZE; i++)
-                    (*jets_7_)[i].a = parameters[7][i];
-                for (i = 0; i < BLOCK_8_SIZE; i++)
-                    (*jets_8_)[i].a = parameters[8][i];
-
-                // call functor
-                (*this->constraint_ptr_)(jets_0_->data(), jets_1_->data(), jets_2_->data(), jets_3_->data(), jets_4_->data(),
-                                         jets_5_->data(), jets_6_->data(), jets_7_->data(), jets_8_->data(),
-                                         residuals_jets_->data());
-
-                // fill the residual array
-                for (i = 0; i < MEASUREMENT_SIZE; i++)
-                    residuals[i] = (*residuals_jets_)[i].a;
-
-                // fill the jacobian matrices
-                for (i = 0; i<this->n_blocks_; i++)
-                    if (jacobians[i] != nullptr)
-                        for (unsigned int row = 0; row < MEASUREMENT_SIZE; row++)
-                            std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
-                                      (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + block_sizes_.at(i),
-                                      jacobians[i] + row * block_sizes_.at(i));
-            }
-            return true;
-        }
-};
-
-// SPECIALIZATION 8 BLOCKS
-template <class ConstraintType, const unsigned int MEASUREMENT_SIZE,
-          unsigned int BLOCK_0_SIZE, unsigned int BLOCK_1_SIZE, unsigned int BLOCK_2_SIZE, unsigned int BLOCK_3_SIZE, unsigned int BLOCK_4_SIZE,
-          unsigned int BLOCK_5_SIZE, unsigned int BLOCK_6_SIZE, unsigned int BLOCK_7_SIZE>
-class AutoDiffCostFunctionWrapperBase<ConstraintType, MEASUREMENT_SIZE,
-                                  BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, BLOCK_3_SIZE, BLOCK_4_SIZE,
-                                  BLOCK_5_SIZE, BLOCK_6_SIZE, BLOCK_7_SIZE, 0, 0>
-    : public ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                               BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,
-                               BLOCK_5_SIZE,BLOCK_6_SIZE,BLOCK_7_SIZE,0,0>
-{
-    typedef ceres::Jet<Scalar, BLOCK_0_SIZE + BLOCK_1_SIZE + BLOCK_2_SIZE + BLOCK_3_SIZE + BLOCK_4_SIZE +
-                                   BLOCK_5_SIZE + BLOCK_6_SIZE + BLOCK_7_SIZE> WolfJet;
-
-    protected:
-        ConstraintType* constraint_ptr_;
-        unsigned int n_blocks_;
-        std::vector<unsigned int> block_sizes_, jacobian_locations_;
-        std::array<WolfJet, BLOCK_0_SIZE>* jets_0_;
-        std::array<WolfJet, BLOCK_1_SIZE>* jets_1_;
-        std::array<WolfJet, BLOCK_2_SIZE>* jets_2_;
-        std::array<WolfJet, BLOCK_3_SIZE>* jets_3_;
-        std::array<WolfJet, BLOCK_4_SIZE>* jets_4_;
-        std::array<WolfJet, BLOCK_5_SIZE>* jets_5_;
-        std::array<WolfJet, BLOCK_6_SIZE>* jets_6_;
-        std::array<WolfJet, BLOCK_7_SIZE>* jets_7_;
-        std::array<WolfJet, MEASUREMENT_SIZE>* residuals_jets_;
-
-    public:
-
-        AutoDiffCostFunctionWrapperBase(ConstraintType* _constraint_ptr) :
-            ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                                     BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,
-                                     BLOCK_5_SIZE,BLOCK_6_SIZE,BLOCK_7_SIZE,0,0>(),
-            constraint_ptr_(_constraint_ptr),
-            n_blocks_(8),
-            block_sizes_({BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, BLOCK_3_SIZE, BLOCK_4_SIZE,
-                          BLOCK_5_SIZE, BLOCK_6_SIZE, BLOCK_7_SIZE}),
-            jacobian_locations_({0,
-                                 BLOCK_0_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE+BLOCK_5_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE+BLOCK_5_SIZE+BLOCK_6_SIZE}),
-            jets_0_(new std::array<WolfJet, BLOCK_0_SIZE>),
-            jets_1_(new std::array<WolfJet, BLOCK_1_SIZE>),
-            jets_2_(new std::array<WolfJet, BLOCK_2_SIZE>),
-            jets_3_(new std::array<WolfJet, BLOCK_3_SIZE>),
-            jets_4_(new std::array<WolfJet, BLOCK_4_SIZE>),
-            jets_5_(new std::array<WolfJet, BLOCK_5_SIZE>),
-            jets_6_(new std::array<WolfJet, BLOCK_6_SIZE>),
-            jets_7_(new std::array<WolfJet, BLOCK_7_SIZE>),
-            residuals_jets_(new std::array<WolfJet, MEASUREMENT_SIZE>)
-        {
-            // initialize jets
-            unsigned int i, last_jet_idx = 0;
-            for (i = 0; i < BLOCK_0_SIZE; i++)
-                (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_1_SIZE; i++)
-                (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_2_SIZE; i++)
-                (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_3_SIZE; i++)
-                (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_4_SIZE; i++)
-                (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_5_SIZE; i++)
-                (*jets_5_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_6_SIZE; i++)
-                (*jets_6_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_7_SIZE; i++)
-                (*jets_7_)[i] = WolfJet(0, last_jet_idx++);
-        };
-
-        virtual ~AutoDiffCostFunctionWrapperBase()
-        {
-            delete jets_0_;
-            delete jets_1_;
-            delete jets_2_;
-            delete jets_3_;
-            delete jets_4_;
-            delete jets_5_;
-            delete jets_6_;
-            delete jets_7_;
-            delete residuals_jets_;
-        };
-
-        virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
-        {
-            // only residuals
-            if (jacobians == nullptr)
-                (*this->constraint_ptr_)(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4],
-                                         parameters[5], parameters[6], parameters[7], residuals);
-
-            // also compute jacobians
-            else
-            {
-                // update jets real part
-                unsigned int i;
-                for (i = 0; i < BLOCK_0_SIZE; i++)
-                    (*jets_0_)[i].a = parameters[0][i];
-                for (i = 0; i < BLOCK_1_SIZE; i++)
-                    (*jets_1_)[i].a = parameters[1][i];
-                for (i = 0; i < BLOCK_2_SIZE; i++)
-                    (*jets_2_)[i].a = parameters[2][i];
-                for (i = 0; i < BLOCK_3_SIZE; i++)
-                    (*jets_3_)[i].a = parameters[3][i];
-                for (i = 0; i < BLOCK_4_SIZE; i++)
-                    (*jets_4_)[i].a = parameters[4][i];
-                for (i = 0; i < BLOCK_5_SIZE; i++)
-                    (*jets_5_)[i].a = parameters[5][i];
-                for (i = 0; i < BLOCK_6_SIZE; i++)
-                    (*jets_6_)[i].a = parameters[6][i];
-                for (i = 0; i < BLOCK_7_SIZE; i++)
-                    (*jets_7_)[i].a = parameters[7][i];
-
-                // call functor
-                (*this->constraint_ptr_)(jets_0_->data(), jets_1_->data(), jets_2_->data(), jets_3_->data(), jets_4_->data(),
-                                         jets_5_->data(), jets_6_->data(), jets_7_->data(),
-                                         residuals_jets_->data());
-
-                // fill the residual array
-                for (i = 0; i < MEASUREMENT_SIZE; i++)
-                    residuals[i] = (*residuals_jets_)[i].a;
-
-                // fill the jacobian matrices
-                for (i = 0; i<n_blocks_; i++)
-                    if (jacobians[i] != nullptr)
-                        for (unsigned int row = 0; row < MEASUREMENT_SIZE; row++)
-                            std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
-                                      (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + block_sizes_.at(i),
-                                      jacobians[i] + row * block_sizes_.at(i));
-            }
-            return true;
-        }
-};
-
-// SPECIALIZATION 7 BLOCKS
-template <class ConstraintType, const unsigned int MEASUREMENT_SIZE,
-          unsigned int BLOCK_0_SIZE, unsigned int BLOCK_1_SIZE, unsigned int BLOCK_2_SIZE, unsigned int BLOCK_3_SIZE, unsigned int BLOCK_4_SIZE,
-          unsigned int BLOCK_5_SIZE, unsigned int BLOCK_6_SIZE>
-class AutoDiffCostFunctionWrapperBase<ConstraintType, MEASUREMENT_SIZE,
-                                  BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, BLOCK_3_SIZE, BLOCK_4_SIZE,
-                                  BLOCK_5_SIZE, BLOCK_6_SIZE, 0, 0, 0>
-    : public ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                               BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,
-                               BLOCK_5_SIZE,BLOCK_6_SIZE,0,0,0>
-{
-    typedef ceres::Jet<Scalar, BLOCK_0_SIZE + BLOCK_1_SIZE + BLOCK_2_SIZE + BLOCK_3_SIZE + BLOCK_4_SIZE +
-                                   BLOCK_5_SIZE + BLOCK_6_SIZE> WolfJet;
-
-    protected:
-        ConstraintType* constraint_ptr_;
-        unsigned int n_blocks_;
-        std::vector<unsigned int> block_sizes_, jacobian_locations_;
-        std::array<WolfJet, BLOCK_0_SIZE>* jets_0_;
-        std::array<WolfJet, BLOCK_1_SIZE>* jets_1_;
-        std::array<WolfJet, BLOCK_2_SIZE>* jets_2_;
-        std::array<WolfJet, BLOCK_3_SIZE>* jets_3_;
-        std::array<WolfJet, BLOCK_4_SIZE>* jets_4_;
-        std::array<WolfJet, BLOCK_5_SIZE>* jets_5_;
-        std::array<WolfJet, BLOCK_6_SIZE>* jets_6_;
-        std::array<WolfJet, MEASUREMENT_SIZE>* residuals_jets_;
-
-    public:
-
-        AutoDiffCostFunctionWrapperBase(ConstraintType* _constraint_ptr) :
-            ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                                     BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,
-                                     BLOCK_5_SIZE,BLOCK_6_SIZE,0,0,0>(),
-            constraint_ptr_(_constraint_ptr),
-            n_blocks_(7),
-            block_sizes_({BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, BLOCK_3_SIZE, BLOCK_4_SIZE,
-                          BLOCK_5_SIZE, BLOCK_6_SIZE}),
-            jacobian_locations_({0,
-                                 BLOCK_0_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE+BLOCK_5_SIZE}),
-            jets_0_(new std::array<WolfJet, BLOCK_0_SIZE>),
-            jets_1_(new std::array<WolfJet, BLOCK_1_SIZE>),
-            jets_2_(new std::array<WolfJet, BLOCK_2_SIZE>),
-            jets_3_(new std::array<WolfJet, BLOCK_3_SIZE>),
-            jets_4_(new std::array<WolfJet, BLOCK_4_SIZE>),
-            jets_5_(new std::array<WolfJet, BLOCK_5_SIZE>),
-            jets_6_(new std::array<WolfJet, BLOCK_6_SIZE>),
-            residuals_jets_(new std::array<WolfJet, MEASUREMENT_SIZE>)
-        {
-            // initialize jets
-            unsigned int i, last_jet_idx = 0;
-            for (i = 0; i < BLOCK_0_SIZE; i++)
-                (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_1_SIZE; i++)
-                (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_2_SIZE; i++)
-                (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_3_SIZE; i++)
-                (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_4_SIZE; i++)
-                (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_5_SIZE; i++)
-                (*jets_5_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_6_SIZE; i++)
-                (*jets_6_)[i] = WolfJet(0, last_jet_idx++);
-        };
-
-        virtual ~AutoDiffCostFunctionWrapperBase()
-        {
-            delete jets_0_;
-            delete jets_1_;
-            delete jets_2_;
-            delete jets_3_;
-            delete jets_4_;
-            delete jets_5_;
-            delete jets_6_;
-            delete residuals_jets_;
-        };
-
-        virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
-        {
-            // only residuals
-            if (jacobians == nullptr)
-                (*this->constraint_ptr_)(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4],
-                                         parameters[5], parameters[6], residuals);
-
-            // also compute jacobians
-            else
-            {
-                // update jets real part
-                unsigned int i;
-                for (i = 0; i < BLOCK_0_SIZE; i++)
-                    (*jets_0_)[i].a = parameters[0][i];
-                for (i = 0; i < BLOCK_1_SIZE; i++)
-                    (*jets_1_)[i].a = parameters[1][i];
-                for (i = 0; i < BLOCK_2_SIZE; i++)
-                    (*jets_2_)[i].a = parameters[2][i];
-                for (i = 0; i < BLOCK_3_SIZE; i++)
-                    (*jets_3_)[i].a = parameters[3][i];
-                for (i = 0; i < BLOCK_4_SIZE; i++)
-                    (*jets_4_)[i].a = parameters[4][i];
-                for (i = 0; i < BLOCK_5_SIZE; i++)
-                    (*jets_5_)[i].a = parameters[5][i];
-                for (i = 0; i < BLOCK_6_SIZE; i++)
-                    (*jets_6_)[i].a = parameters[6][i];
-
-                // call functor
-                (*this->constraint_ptr_)(jets_0_->data(), jets_1_->data(), jets_2_->data(), jets_3_->data(), jets_4_->data(),
-                                         jets_5_->data(), jets_6_->data(),
-                                         residuals_jets_->data());
-
-                // fill the residual array
-                for (i = 0; i < MEASUREMENT_SIZE; i++)
-                    residuals[i] = (*residuals_jets_)[i].a;
-
-                // fill the jacobian matrices
-                for (i = 0; i<n_blocks_; i++)
-                    if (jacobians[i] != nullptr)
-                        for (unsigned int row = 0; row < MEASUREMENT_SIZE; row++)
-                            std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
-                                      (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + block_sizes_.at(i),
-                                      jacobians[i] + row * block_sizes_.at(i));
-            }
-            return true;
-        }
-};
-
-// SPECIALIZATION 6 BLOCKS
-template <class ConstraintType, const unsigned int MEASUREMENT_SIZE,
-          unsigned int BLOCK_0_SIZE, unsigned int BLOCK_1_SIZE, unsigned int BLOCK_2_SIZE, unsigned int BLOCK_3_SIZE, unsigned int BLOCK_4_SIZE,
-          unsigned int BLOCK_5_SIZE>
-class AutoDiffCostFunctionWrapperBase<ConstraintType, MEASUREMENT_SIZE,
-                                  BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, BLOCK_3_SIZE, BLOCK_4_SIZE,
-                                  BLOCK_5_SIZE, 0, 0, 0, 0>
-    : public ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                               BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,
-                               BLOCK_5_SIZE,0,0,0,0>
-{
-    typedef ceres::Jet<Scalar, BLOCK_0_SIZE + BLOCK_1_SIZE + BLOCK_2_SIZE + BLOCK_3_SIZE + BLOCK_4_SIZE +
-                                   BLOCK_5_SIZE> WolfJet;
-
-    protected:
-        ConstraintType* constraint_ptr_;
-        unsigned int n_blocks_;
-        std::vector<unsigned int> block_sizes_, jacobian_locations_;
-        std::array<WolfJet, BLOCK_0_SIZE>* jets_0_;
-        std::array<WolfJet, BLOCK_1_SIZE>* jets_1_;
-        std::array<WolfJet, BLOCK_2_SIZE>* jets_2_;
-        std::array<WolfJet, BLOCK_3_SIZE>* jets_3_;
-        std::array<WolfJet, BLOCK_4_SIZE>* jets_4_;
-        std::array<WolfJet, BLOCK_5_SIZE>* jets_5_;
-        std::array<WolfJet, MEASUREMENT_SIZE>* residuals_jets_;
-
-    public:
-
-        AutoDiffCostFunctionWrapperBase(ConstraintType* _constraint_ptr) :
-            ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                                     BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,
-                                     BLOCK_5_SIZE,0,0,0,0>(),
-            constraint_ptr_(_constraint_ptr),
-            n_blocks_(6),
-            block_sizes_({BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, BLOCK_3_SIZE, BLOCK_4_SIZE,
-                          BLOCK_5_SIZE}),
-            jacobian_locations_({0,
-                                 BLOCK_0_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE+BLOCK_4_SIZE}),
-            jets_0_(new std::array<WolfJet, BLOCK_0_SIZE>),
-            jets_1_(new std::array<WolfJet, BLOCK_1_SIZE>),
-            jets_2_(new std::array<WolfJet, BLOCK_2_SIZE>),
-            jets_3_(new std::array<WolfJet, BLOCK_3_SIZE>),
-            jets_4_(new std::array<WolfJet, BLOCK_4_SIZE>),
-            jets_5_(new std::array<WolfJet, BLOCK_5_SIZE>),
-            residuals_jets_(new std::array<WolfJet, MEASUREMENT_SIZE>)
-        {
-            // initialize jets
-            unsigned int i, last_jet_idx = 0;
-            for (i = 0; i < BLOCK_0_SIZE; i++)
-                (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_1_SIZE; i++)
-                (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_2_SIZE; i++)
-                (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_3_SIZE; i++)
-                (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_4_SIZE; i++)
-                (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_5_SIZE; i++)
-                (*jets_5_)[i] = WolfJet(0, last_jet_idx++);
-        };
-
-        virtual ~AutoDiffCostFunctionWrapperBase()
-        {
-            delete jets_0_;
-            delete jets_1_;
-            delete jets_2_;
-            delete jets_3_;
-            delete jets_4_;
-            delete jets_5_;
-            delete residuals_jets_;
-        };
-
-        virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
-        {
-            // only residuals
-            if (jacobians == nullptr)
-                (*this->constraint_ptr_)(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4],
-                                         parameters[5], residuals);
-
-            // also compute jacobians
-            else
-            {
-                // update jets real part
-                unsigned int i;
-                for (i = 0; i < BLOCK_0_SIZE; i++)
-                    (*jets_0_)[i].a = parameters[0][i];
-                for (i = 0; i < BLOCK_1_SIZE; i++)
-                    (*jets_1_)[i].a = parameters[1][i];
-                for (i = 0; i < BLOCK_2_SIZE; i++)
-                    (*jets_2_)[i].a = parameters[2][i];
-                for (i = 0; i < BLOCK_3_SIZE; i++)
-                    (*jets_3_)[i].a = parameters[3][i];
-                for (i = 0; i < BLOCK_4_SIZE; i++)
-                    (*jets_4_)[i].a = parameters[4][i];
-                for (i = 0; i < BLOCK_5_SIZE; i++)
-                    (*jets_5_)[i].a = parameters[5][i];
-
-                // call functor
-                (*this->constraint_ptr_)(jets_0_->data(), jets_1_->data(), jets_2_->data(), jets_3_->data(), jets_4_->data(),
-                                         jets_5_->data(), residuals_jets_->data());
-
-                // fill the residual array
-                for (i = 0; i < MEASUREMENT_SIZE; i++)
-                    residuals[i] = (*residuals_jets_)[i].a;
-
-                // fill the jacobian matrices
-                for (i = 0; i<n_blocks_; i++)
-                    if (jacobians[i] != nullptr)
-                        for (unsigned int row = 0; row < MEASUREMENT_SIZE; row++)
-                            std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
-                                      (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + block_sizes_.at(i),
-                                      jacobians[i] + row * block_sizes_.at(i));
-            }
-            return true;
-        }
-};
-
-// SPECIALIZATION 5 BLOCKS
-template <class ConstraintType, const unsigned int MEASUREMENT_SIZE,
-          unsigned int BLOCK_0_SIZE, unsigned int BLOCK_1_SIZE, unsigned int BLOCK_2_SIZE, unsigned int BLOCK_3_SIZE, unsigned int BLOCK_4_SIZE>
-class AutoDiffCostFunctionWrapperBase<ConstraintType, MEASUREMENT_SIZE,
-                                  BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, BLOCK_3_SIZE, BLOCK_4_SIZE,
-                                  0, 0, 0, 0, 0>
-    : public ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                               BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,
-                               0,0,0,0,0>
-{
-    typedef ceres::Jet<Scalar, BLOCK_0_SIZE + BLOCK_1_SIZE + BLOCK_2_SIZE + BLOCK_3_SIZE + BLOCK_4_SIZE> WolfJet;
-
-    protected:
-        ConstraintType* constraint_ptr_;
-        unsigned int n_blocks_;
-        std::vector<unsigned int> block_sizes_, jacobian_locations_;
-        std::array<WolfJet, BLOCK_0_SIZE>* jets_0_;
-        std::array<WolfJet, BLOCK_1_SIZE>* jets_1_;
-        std::array<WolfJet, BLOCK_2_SIZE>* jets_2_;
-        std::array<WolfJet, BLOCK_3_SIZE>* jets_3_;
-        std::array<WolfJet, BLOCK_4_SIZE>* jets_4_;
-        std::array<WolfJet, MEASUREMENT_SIZE>* residuals_jets_;
-
-    public:
-
-        AutoDiffCostFunctionWrapperBase(ConstraintType* _constraint_ptr) :
-            ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                                     BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,
-                                     0,0,0,0,0>(),
-            constraint_ptr_(_constraint_ptr),
-            n_blocks_(5),
-            block_sizes_({BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, BLOCK_3_SIZE, BLOCK_4_SIZE}),
-            jacobian_locations_({0,
-                                 BLOCK_0_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE+BLOCK_3_SIZE}),
-            jets_0_(new std::array<WolfJet, BLOCK_0_SIZE>),
-            jets_1_(new std::array<WolfJet, BLOCK_1_SIZE>),
-            jets_2_(new std::array<WolfJet, BLOCK_2_SIZE>),
-            jets_3_(new std::array<WolfJet, BLOCK_3_SIZE>),
-            jets_4_(new std::array<WolfJet, BLOCK_4_SIZE>),
-            residuals_jets_(new std::array<WolfJet, MEASUREMENT_SIZE>)
-        {
-            // initialize jets
-            unsigned int i, last_jet_idx = 0;
-            for (i = 0; i < BLOCK_0_SIZE; i++)
-                (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_1_SIZE; i++)
-                (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_2_SIZE; i++)
-                (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_3_SIZE; i++)
-                (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_4_SIZE; i++)
-                (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
-        };
-
-        virtual ~AutoDiffCostFunctionWrapperBase()
-        {
-            delete jets_0_;
-            delete jets_1_;
-            delete jets_2_;
-            delete jets_3_;
-            delete jets_4_;
-            delete residuals_jets_;
-        };
-
-        virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
-        {
-            // only residuals
-            if (jacobians == nullptr)
-                (*this->constraint_ptr_)(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4],
-                                         residuals);
-
-            // also compute jacobians
-            else
-            {
-                // update jets real part
-                unsigned int i;
-                for (i = 0; i < BLOCK_0_SIZE; i++)
-                    (*jets_0_)[i].a = parameters[0][i];
-                for (i = 0; i < BLOCK_1_SIZE; i++)
-                    (*jets_1_)[i].a = parameters[1][i];
-                for (i = 0; i < BLOCK_2_SIZE; i++)
-                    (*jets_2_)[i].a = parameters[2][i];
-                for (i = 0; i < BLOCK_3_SIZE; i++)
-                    (*jets_3_)[i].a = parameters[3][i];
-                for (i = 0; i < BLOCK_4_SIZE; i++)
-                    (*jets_4_)[i].a = parameters[4][i];
-
-                // call functor
-                (*this->constraint_ptr_)(jets_0_->data(), jets_1_->data(), jets_2_->data(), jets_3_->data(), jets_4_->data(),
-                                         residuals_jets_->data());
-
-                // fill the residual array
-                for (i = 0; i < MEASUREMENT_SIZE; i++)
-                    residuals[i] = (*residuals_jets_)[i].a;
-
-                // fill the jacobian matrices
-                for (i = 0; i<n_blocks_; i++)
-                    if (jacobians[i] != nullptr)
-                        for (unsigned int row = 0; row < MEASUREMENT_SIZE; row++)
-                            std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
-                                      (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + block_sizes_.at(i),
-                                      jacobians[i] + row * block_sizes_.at(i));
-            }
-            return true;
-        }
-};
-
-// SPECIALIZATION 4 BLOCKS
-template <class ConstraintType, const unsigned int MEASUREMENT_SIZE,
-          unsigned int BLOCK_0_SIZE, unsigned int BLOCK_1_SIZE, unsigned int BLOCK_2_SIZE, unsigned int BLOCK_3_SIZE>
-class AutoDiffCostFunctionWrapperBase<ConstraintType, MEASUREMENT_SIZE,
-                                  BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, BLOCK_3_SIZE, 0,
-                                  0, 0, 0, 0, 0>
-    : public ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                               BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,0,
-                               0,0,0,0,0>
-{
-    typedef ceres::Jet<Scalar, BLOCK_0_SIZE + BLOCK_1_SIZE + BLOCK_2_SIZE + BLOCK_3_SIZE> WolfJet;
-
-    protected:
-        ConstraintType* constraint_ptr_;
-        unsigned int n_blocks_;
-        std::vector<unsigned int> block_sizes_, jacobian_locations_;
-        std::array<WolfJet, BLOCK_0_SIZE>* jets_0_;
-        std::array<WolfJet, BLOCK_1_SIZE>* jets_1_;
-        std::array<WolfJet, BLOCK_2_SIZE>* jets_2_;
-        std::array<WolfJet, BLOCK_3_SIZE>* jets_3_;
-        std::array<WolfJet, MEASUREMENT_SIZE>* residuals_jets_;
-
-    public:
-
-        AutoDiffCostFunctionWrapperBase(ConstraintType* _constraint_ptr) :
-            ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                                     BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,0,
-                                     0,0,0,0,0>(),
-            constraint_ptr_(_constraint_ptr),
-            n_blocks_(4),
-            block_sizes_({BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, BLOCK_3_SIZE}),
-            jacobian_locations_({0,
-                                 BLOCK_0_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE+BLOCK_2_SIZE}),
-            jets_0_(new std::array<WolfJet, BLOCK_0_SIZE>),
-            jets_1_(new std::array<WolfJet, BLOCK_1_SIZE>),
-            jets_2_(new std::array<WolfJet, BLOCK_2_SIZE>),
-            jets_3_(new std::array<WolfJet, BLOCK_3_SIZE>),
-            residuals_jets_(new std::array<WolfJet, MEASUREMENT_SIZE>)
-        {
-            // initialize jets
-            unsigned int i, last_jet_idx = 0;
-            for (i = 0; i < BLOCK_0_SIZE; i++)
-                (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_1_SIZE; i++)
-                (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_2_SIZE; i++)
-                (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_3_SIZE; i++)
-                (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
-        };
-
-        virtual ~AutoDiffCostFunctionWrapperBase()
-        {
-            delete jets_0_;
-            delete jets_1_;
-            delete jets_2_;
-            delete jets_3_;
-            delete residuals_jets_;
-        };
-
-        virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
-        {
-            // only residuals
-            if (jacobians == nullptr)
-                (*this->constraint_ptr_)(parameters[0], parameters[1], parameters[2], parameters[3], residuals);
-            // also compute jacobians
-            else
-            {
-                // update jets real part
-                unsigned int i;
-                for (i = 0; i < BLOCK_0_SIZE; i++)
-                    (*jets_0_)[i].a = parameters[0][i];
-                for (i = 0; i < BLOCK_1_SIZE; i++)
-                    (*jets_1_)[i].a = parameters[1][i];
-                for (i = 0; i < BLOCK_2_SIZE; i++)
-                    (*jets_2_)[i].a = parameters[2][i];
-                for (i = 0; i < BLOCK_3_SIZE; i++)
-                    (*jets_3_)[i].a = parameters[3][i];
-
-                // call functor
-                (*this->constraint_ptr_)(jets_0_->data(), jets_1_->data(), jets_2_->data(), jets_3_->data(), residuals_jets_->data());
-
-                // fill the residual array
-                for (i = 0; i < MEASUREMENT_SIZE; i++)
-                    residuals[i] = (*residuals_jets_)[i].a;
-
-                // fill the jacobian matrices
-                for (i = 0; i<n_blocks_; i++)
-                    if (jacobians[i] != nullptr)
-                        for (unsigned int row = 0; row < MEASUREMENT_SIZE; row++)
-                            std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
-                                      (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + block_sizes_.at(i),
-                                      jacobians[i] + row * block_sizes_.at(i));
-            }
-            return true;
-        }
-};
-
-// SPECIALIZATION 3 BLOCKS
-template <class ConstraintType, const unsigned int MEASUREMENT_SIZE,
-          unsigned int BLOCK_0_SIZE, unsigned int BLOCK_1_SIZE, unsigned int BLOCK_2_SIZE>
-class AutoDiffCostFunctionWrapperBase<ConstraintType, MEASUREMENT_SIZE,
-                                  BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE, 0, 0,
-                                  0, 0, 0, 0, 0>
-    : public ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                               BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,0,0,
-                               0,0,0,0,0>
-{
-    typedef ceres::Jet<Scalar, BLOCK_0_SIZE + BLOCK_1_SIZE + BLOCK_2_SIZE> WolfJet;
-
-    protected:
-        ConstraintType* constraint_ptr_;
-        unsigned int n_blocks_;
-        std::vector<unsigned int> block_sizes_, jacobian_locations_;
-        std::array<WolfJet, BLOCK_0_SIZE>* jets_0_;
-        std::array<WolfJet, BLOCK_1_SIZE>* jets_1_;
-        std::array<WolfJet, BLOCK_2_SIZE>* jets_2_;
-        std::array<WolfJet, MEASUREMENT_SIZE>* residuals_jets_;
-
-    public:
-
-        AutoDiffCostFunctionWrapperBase(ConstraintType* _constraint_ptr) :
-            ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                                     BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,0,0,
-                                     0,0,0,0,0>(),
-            constraint_ptr_(_constraint_ptr),
-            n_blocks_(3),
-            block_sizes_({BLOCK_0_SIZE, BLOCK_1_SIZE, BLOCK_2_SIZE}),
-            jacobian_locations_({0,
-                                 BLOCK_0_SIZE,
-                                 BLOCK_0_SIZE+BLOCK_1_SIZE}),
-            jets_0_(new std::array<WolfJet, BLOCK_0_SIZE>),
-            jets_1_(new std::array<WolfJet, BLOCK_1_SIZE>),
-            jets_2_(new std::array<WolfJet, BLOCK_2_SIZE>),
-            residuals_jets_(new std::array<WolfJet, MEASUREMENT_SIZE>)
-        {
-            // initialize jets
-            unsigned int i, last_jet_idx = 0;
-            for (i = 0; i < BLOCK_0_SIZE; i++)
-                (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_1_SIZE; i++)
-                (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_2_SIZE; i++)
-                (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
-
-        };
-
-        virtual ~AutoDiffCostFunctionWrapperBase()
-        {
-            delete jets_0_;
-            delete jets_1_;
-            delete jets_2_;
-            delete residuals_jets_;
-        };
-
-        virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
-        {
-            // only residuals
-            if (jacobians == nullptr)
-                (*this->constraint_ptr_)(parameters[0], parameters[1], parameters[2], residuals);
-
-            // also compute jacobians
-            else
-            {
-                // update jets real part
-                unsigned int i;
-                for (i = 0; i < BLOCK_0_SIZE; i++)
-                    (*jets_0_)[i].a = parameters[0][i];
-                for (i = 0; i < BLOCK_1_SIZE; i++)
-                    (*jets_1_)[i].a = parameters[1][i];
-                for (i = 0; i < BLOCK_2_SIZE; i++)
-                    (*jets_2_)[i].a = parameters[2][i];
-
-                // call functor
-                (*this->constraint_ptr_)(jets_0_->data(), jets_1_->data(), jets_2_->data(), residuals_jets_->data());
-
-                // fill the residual array
-                for (i = 0; i < MEASUREMENT_SIZE; i++)
-                    residuals[i] = (*residuals_jets_)[i].a;
-
-                // fill the jacobian matrices
-                for (i = 0; i<n_blocks_; i++)
-                    if (jacobians[i] != nullptr)
-                        for (unsigned int row = 0; row < MEASUREMENT_SIZE; row++)
-                            std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
-                                      (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + block_sizes_.at(i),
-                                      jacobians[i] + row * block_sizes_.at(i));
-            }
-            return true;
-        }
-};
-
-// SPECIALIZATION 2 BLOCKS
-template <class ConstraintType, const unsigned int MEASUREMENT_SIZE,
-          unsigned int BLOCK_0_SIZE, unsigned int BLOCK_1_SIZE>
-class AutoDiffCostFunctionWrapperBase<ConstraintType, MEASUREMENT_SIZE,
-                                  BLOCK_0_SIZE, BLOCK_1_SIZE, 0, 0, 0,
-                                  0, 0, 0, 0, 0>
-    : public ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                               BLOCK_0_SIZE,BLOCK_1_SIZE,0,0,0,
-                               0,0,0,0,0>
-{
-    typedef ceres::Jet<Scalar, BLOCK_0_SIZE + BLOCK_1_SIZE> WolfJet;
-
-    protected:
-        ConstraintType* constraint_ptr_;
-        unsigned int n_blocks_;
-        std::vector<unsigned int> block_sizes_, jacobian_locations_;
-        std::array<WolfJet, BLOCK_0_SIZE>* jets_0_;
-        std::array<WolfJet, BLOCK_1_SIZE>* jets_1_;
-        std::array<WolfJet, MEASUREMENT_SIZE>* residuals_jets_;
-
-    public:
-
-        AutoDiffCostFunctionWrapperBase(ConstraintType* _constraint_ptr) :
-            ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                                     BLOCK_0_SIZE,BLOCK_1_SIZE,0,0,0,
-                                     0,0,0,0,0>(),
-            constraint_ptr_(_constraint_ptr),
-            n_blocks_(2),
-            block_sizes_({BLOCK_0_SIZE, BLOCK_1_SIZE}),
-            jacobian_locations_({0,
-                                 BLOCK_0_SIZE}),
-            jets_0_(new std::array<WolfJet, BLOCK_0_SIZE>),
-            jets_1_(new std::array<WolfJet, BLOCK_1_SIZE>),
-            residuals_jets_(new std::array<WolfJet, MEASUREMENT_SIZE>)
-        {
-            // initialize jets
-            unsigned int i, last_jet_idx = 0;
-            for (i = 0; i < BLOCK_0_SIZE; i++)
-                (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
-            for (i = 0; i < BLOCK_1_SIZE; i++)
-                (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
-        };
-
-        virtual ~AutoDiffCostFunctionWrapperBase()
-        {
-            delete jets_0_;
-            delete jets_1_;
-            delete residuals_jets_;
-        };
-
-        virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
-        {
-            // only residuals
-            if (jacobians == nullptr)
-                (*this->constraint_ptr_)(parameters[0], parameters[1], residuals);
-
-            // also compute jacobians
-            else
-            {
-                // update jets real part
-                unsigned int i;
-                for (i = 0; i < BLOCK_0_SIZE; i++)
-                    (*jets_0_)[i].a = parameters[0][i];
-                for (i = 0; i < BLOCK_1_SIZE; i++)
-                    (*jets_1_)[i].a = parameters[1][i];
-
-                // call functor
-                (*this->constraint_ptr_)(jets_0_->data(), jets_1_->data(), residuals_jets_->data());
-
-                // fill the residual array
-                for (i = 0; i < MEASUREMENT_SIZE; i++)
-                    residuals[i] = (*residuals_jets_)[i].a;
-
-                // fill the jacobian matrices
-                for (i = 0; i<n_blocks_; i++)
-                    if (jacobians[i] != nullptr)
-                        for (unsigned int row = 0; row < MEASUREMENT_SIZE; row++)
-                            std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
-                                      (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + block_sizes_.at(i),
-                                      jacobians[i] + row * block_sizes_.at(i));
-            }
-            return true;
-        }
-};
-
-// SPECIALIZATION 1 BLOCK
-template <class ConstraintType, const unsigned int MEASUREMENT_SIZE,
-          unsigned int BLOCK_0_SIZE>
-class AutoDiffCostFunctionWrapperBase<ConstraintType, MEASUREMENT_SIZE,
-                                  BLOCK_0_SIZE, 0, 0, 0, 0,
-                                  0, 0, 0, 0, 0>
-    : public ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                               BLOCK_0_SIZE,0,0,0,0,
-                               0,0,0,0,0>
-{
-    typedef ceres::Jet<Scalar, BLOCK_0_SIZE> WolfJet;
-
-    protected:
-        ConstraintType* constraint_ptr_;
-        unsigned int n_blocks_;
-        std::vector<unsigned int> block_sizes_, jacobian_locations_;
-        std::array<WolfJet, BLOCK_0_SIZE>* jets_0_;
-        std::array<WolfJet, MEASUREMENT_SIZE>* residuals_jets_;
-
-    public:
-
-        AutoDiffCostFunctionWrapperBase(ConstraintType* _constraint_ptr) :
-            ceres::SizedCostFunction<MEASUREMENT_SIZE,
-                                     BLOCK_0_SIZE,0,0,0,0,
-                                     0,0,0,0,0>(),
-            constraint_ptr_(_constraint_ptr),
-            n_blocks_(1),
-            block_sizes_({BLOCK_0_SIZE}),
-            jacobian_locations_({0}),
-            jets_0_(new std::array<WolfJet, BLOCK_0_SIZE>),
-            residuals_jets_(new std::array<WolfJet, MEASUREMENT_SIZE>)
-        {
-            // initialize jets
-            unsigned int i, last_jet_idx = 0;
-            for (i = 0; i < BLOCK_0_SIZE; i++)
-                (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
-        };
-
-        virtual ~AutoDiffCostFunctionWrapperBase()
-        {
-            delete jets_0_;
-            delete residuals_jets_;
-        };
-
-        virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
-        {
-            // only residuals
-            if (jacobians == nullptr)
-                (*this->constraint_ptr_)(parameters[0], residuals);
-            // also compute jacobians
-            else
-            {
-                // update jets real part
-                unsigned int i;
-                for (i = 0; i < BLOCK_0_SIZE; i++)
-                    (*jets_0_)[i].a = parameters[0][i];
-
-                // call functor
-                (*this->constraint_ptr_)(jets_0_->data(), residuals_jets_->data());
-
-                // fill the residual array
-                for (i = 0; i < MEASUREMENT_SIZE; i++)
-                    residuals[i] = (*residuals_jets_)[i].a;
-
-                // fill the jacobian matrices
-                for (i = 0; i<n_blocks_; i++)
-                    if (jacobians[i] != nullptr)
-                        for (unsigned int row = 0; row < MEASUREMENT_SIZE; row++)
-                            std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
-                                      (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + block_sizes_.at(i),
-                                      jacobians[i] + row * block_sizes_.at(i));
-            }
-            return true;
-        }
-};
-
-} // namespace wolf
-
-#endif /* TRUNK_SRC_AUTODIFF_COST_FUNCTION_WRAPPER_BASE_H_ */
diff --git a/src/ceres_wrapper/ceres_manager.cpp b/src/ceres_wrapper/ceres_manager.cpp
index a66b289b7a4777401c608818447feaf404d9e2d0..acf4585d32b2310294be3da40ea4c236503c4d78 100644
--- a/src/ceres_wrapper/ceres_manager.cpp
+++ b/src/ceres_wrapper/ceres_manager.cpp
@@ -1,14 +1,14 @@
 #include "ceres_manager.h"
+#include "create_numeric_diff_cost_function.h"
 #include "../trajectory_base.h"
 #include "../map_base.h"
 #include "../landmark_base.h"
 
 namespace wolf {
 
-CeresManager::CeresManager(ProblemPtr _wolf_problem, const ceres::Solver::Options& _ceres_options, const bool _use_wolf_auto_diff) :
-    ceres_options_(_ceres_options),
-    wolf_problem_(_wolf_problem),
-    use_wolf_auto_diff_(_use_wolf_auto_diff)
+CeresManager::CeresManager(ProblemPtr _wolf_problem, const ceres::Solver::Options& _ceres_options) :
+    SolverManager(_wolf_problem),
+    ceres_options_(_ceres_options)
 {
     ceres::Covariance::Options covariance_options;
     #if CERES_VERSION_MINOR >= 13
@@ -25,7 +25,6 @@ CeresManager::CeresManager(ProblemPtr _wolf_problem, const ceres::Solver::Option
     covariance_ = new ceres::Covariance(covariance_options);
 
     ceres::Problem::Options problem_options;
-
     problem_options.cost_function_ownership = ceres::DO_NOT_TAKE_OWNERSHIP;
     problem_options.loss_function_ownership = ceres::TAKE_OWNERSHIP;
     problem_options.local_parameterization_ownership = ceres::DO_NOT_TAKE_OWNERSHIP;
@@ -36,11 +35,9 @@ CeresManager::~CeresManager()
 {
 //	std::cout << "ceres residual blocks:   " << ceres_problem_->NumResidualBlocks() << std::endl;
 //	std::cout << "ceres parameter blocks:  " << ceres_problem_->NumParameterBlocks() << std::endl;
-    while (!id_2_residual_idx_.empty())
-        removeConstraint(id_2_residual_idx_.begin()->first);
+    while (!ctr_2_residual_idx_.empty())
+        removeConstraint(ctr_2_residual_idx_.begin()->first);
 //	std::cout << "all residuals removed! \n";
-    removeAllStateBlocks();
-//    std::cout << "all parameter blocks removed! \n";
 
 	delete covariance_;
     //std::cout << "covariance deleted! \n";
@@ -48,23 +45,28 @@ CeresManager::~CeresManager()
     //std::cout << "ceres problem deleted! \n";
 }
 
-ceres::Solver::Summary CeresManager::solve()
+std::string CeresManager::solve(const unsigned int& _report_level)
 {
-	//std::cout << "Residual blocks: " << ceres_problem_->NumResidualBlocks() <<  " Parameter blocks: " << ceres_problem_->NumParameterBlocks() << std::endl;
+    //std::cout << "Residual blocks: " << ceres_problem_->NumResidualBlocks() <<  " Parameter blocks: " << ceres_problem_->NumParameterBlocks() << std::endl;
 
     // update problem
-    update();
+        update();
 
     //std::cout << "After Update: Residual blocks: " << ceres_problem_->NumResidualBlocks() <<  " Parameter blocks: " << ceres_problem_->NumParameterBlocks() << std::endl;
 
-	// create summary
-	ceres::Solver::Summary ceres_summary_;
-
-	// run Ceres Solver
-	ceres::Solve(ceres_options_, ceres_problem_, &ceres_summary_);
-	//std::cout << "solved" << std::endl;
-	//return results
-	return ceres_summary_;
+        // run Ceres Solver
+    ceres::Solve(ceres_options_, ceres_problem_, &summary_);
+    //std::cout << "solved" << std::endl;
+
+	//return report
+	if (_report_level == 0)
+	    return std::string();
+    else if (_report_level == 1)
+        return summary_.BriefReport();
+    else if (_report_level == 2)
+        return summary_.FullReport();
+    else
+        throw std::invalid_argument( "Report level should be 0, 1 or 2!" );
 }
 
 void CeresManager::computeCovariances(CovarianceBlocksToBeComputed _blocks)
@@ -102,64 +104,37 @@ void CeresManager::computeCovariances(CovarianceBlocksToBeComputed _blocks)
             }
             // double loop all against all (without repetitions)
             for (unsigned int i = 0; i < all_state_blocks.size(); i++)
-            {
                 for  (unsigned int j = i; j < all_state_blocks.size(); j++)
                 {
                     state_block_pairs.emplace_back(all_state_blocks[i],all_state_blocks[j]);
                     double_pairs.emplace_back(all_state_blocks[i]->getPtr(),all_state_blocks[j]->getPtr());
                 }
-            }
             break;
         }
         case ALL_MARGINALS:
         {
             // first create a vector containing all state blocks
-//            std::vector<StateBlockPtr> all_state_blocks, landmark_state_blocks;
-            //frame state blocks
             for(auto fr_ptr : wolf_problem_->getTrajectoryPtr()->getFrameList())
-            {
                 if (fr_ptr->isKey())
                     for (auto sb : fr_ptr->getStateBlockVec())
                         if (sb)
-                        {
-//                            std::cout << "CeresManager::computeCovariances(): State block @ " << sb.get() << std::endl;
-//                            all_state_blocks.push_back(sb);
                             for(auto sb2 : fr_ptr->getStateBlockVec())
-                            {
                                 if (sb)
                                 {
                                     state_block_pairs.emplace_back(sb, sb2);
                                     double_pairs.emplace_back(sb->getPtr(), sb2->getPtr());
                                     if (sb == sb2) break;
                                 }
-                            }
-                        }
-            }
 
             // landmark state blocks
             for(auto l_ptr : wolf_problem_->getMapPtr()->getLandmarkList())
-            {
-//                landmark_state_blocks = l_ptr->getUsedStateBlockVec();
-//                all_state_blocks.insert(all_state_blocks.end(), landmark_state_blocks.begin(), landmark_state_blocks.end());
-                //all_state_blocks.push_back(l_ptr->getPPtr());
-                //all_state_blocks.push_back(l_ptr->getOPtr());
-
-
                 for (auto sb : l_ptr->getUsedStateBlockVec())
-                {
-//                    std::cout << "CeresManager::computeCovariances(): State block @ " << sb.get() << std::endl;
-//                    all_state_blocks.push_back(sb);
                     for(auto sb2 : l_ptr->getUsedStateBlockVec())
                     {
                         state_block_pairs.emplace_back(sb, sb2);
                         double_pairs.emplace_back(sb->getPtr(), sb2->getPtr());
                         if (sb == sb2) break;
                     }
-                }
-
-
-
-            }
 //            // loop all marginals (PO marginals)
 //            for (unsigned int i = 0; 2*i+1 < all_state_blocks.size(); i++)
 //            {
@@ -230,108 +205,70 @@ void CeresManager::computeCovariances(CovarianceBlocksToBeComputed _blocks)
         std::cout << "WARNING: Couldn't compute covariances!" << std::endl;
 }
 
-void CeresManager::update()
+void CeresManager::computeCovariances(const StateBlockList& st_list)
 {
-	//std::cout << "CeresManager: updating... " << std::endl;
-	//std::cout << wolf_problem_->getStateBlockNotificationList().size() << " state block notifications" << std::endl;
-	//std::cout << wolf_problem_->getConstraintNotificationList().size() << " constraint notifications" << std::endl;
-
-	// REMOVE CONSTRAINTS
-	auto ctr_notification_it = wolf_problem_->getConstraintNotificationList().begin();
-	while ( ctr_notification_it != wolf_problem_->getConstraintNotificationList().end() )
-	{
-		if (ctr_notification_it->notification_ == REMOVE)
-		{
-			removeConstraint(ctr_notification_it->id_);
-			ctr_notification_it = wolf_problem_->getConstraintNotificationList().erase(ctr_notification_it);
-		}
-		else
-			ctr_notification_it++;
-	}
-
-	// REMOVE STATE BLOCKS
-	auto state_notification_it = wolf_problem_->getStateBlockNotificationList().begin();
-	while ( state_notification_it != wolf_problem_->getStateBlockNotificationList().end() )
-	{
-		if (state_notification_it->notification_ == REMOVE)
-		{
-			removeStateBlock((double *)(state_notification_it->scalar_ptr_));
-			state_notification_it = wolf_problem_->getStateBlockNotificationList().erase(state_notification_it);
-		}
-		else
-			state_notification_it++;
-	}
-
-    // ADD/UPDATE STATE BLOCKS
-    while (!wolf_problem_->getStateBlockNotificationList().empty())
-    {
-        switch (wolf_problem_->getStateBlockNotificationList().front().notification_)
+    //std::cout << "CeresManager: computing covariances..." << std::endl;
+
+    // update problem
+    update();
+
+    // CLEAR STORED COVARIANCE BLOCKS IN WOLF PROBLEM
+    wolf_problem_->clearCovariance();
+
+    // CREATE DESIRED COVARIANCES LIST
+    std::vector<std::pair<StateBlockPtr, StateBlockPtr>> state_block_pairs;
+    std::vector<std::pair<const double*, const double*>> double_pairs;
+
+    // double loop all against all (without repetitions)
+    for (auto st_it1 = st_list.begin(); st_it1 != st_list.end(); st_it1++)
+        for (auto st_it2 = st_it1; st_it2 != st_list.end(); st_it2++)
         {
-            case ADD:
-            {
-                addStateBlock(wolf_problem_->getStateBlockNotificationList().front().state_block_ptr_);
-                break;
-            }
-            case UPDATE:
-            {
-                updateStateBlockStatus(wolf_problem_->getStateBlockNotificationList().front().state_block_ptr_);
-                break;
-            }
-            default:
-                throw std::runtime_error("CeresManager::update: State Block notification must be ADD, UPATE or REMOVE.");
+            state_block_pairs.push_back(std::pair<StateBlockPtr, StateBlockPtr>(*st_it1,*st_it2));
+            double_pairs.push_back(std::pair<const double*, const double*>((*st_it1)->getPtr(),(*st_it2)->getPtr()));
         }
-        wolf_problem_->getStateBlockNotificationList().pop_front();
-    }
-    // ADD CONSTRAINTS
-    while (!wolf_problem_->getConstraintNotificationList().empty())
-    {
-        switch (wolf_problem_->getConstraintNotificationList().front().notification_)
+
+    //std::cout << "pairs... " << double_pairs.size() << std::endl;
+
+    // COMPUTE DESIRED COVARIANCES
+    if (covariance_->Compute(double_pairs, ceres_problem_))
+        // STORE DESIRED COVARIANCES
+        for (unsigned int i = 0; i < double_pairs.size(); i++)
         {
-            case ADD:
-            {
-//                std::cout << "adding constraint" << std::endl;
-                addConstraint(wolf_problem_->getConstraintNotificationList().front().constraint_ptr_,wolf_problem_->getConstraintNotificationList().front().id_);
-                //std::cout << "added" << std::endl;
-                break;
-            }
-            default:
-                throw std::runtime_error("CeresManager::update: Constraint notification must be ADD or REMOVE.");
+            Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> cov(state_block_pairs[i].first->getSize(),state_block_pairs[i].second->getSize());
+            covariance_->GetCovarianceBlock(double_pairs[i].first, double_pairs[i].second, cov.data());
+            wolf_problem_->addCovarianceBlock(state_block_pairs[i].first, state_block_pairs[i].second, cov);
+            //std::cout << "getted covariance " << std::endl << cov << std::endl;
         }
-        wolf_problem_->getConstraintNotificationList().pop_front();
-    }
-//	std::cout << "all constraints added" << std::endl;
-//	std::cout << "ceres residual blocks:   " << ceres_problem_->NumResidualBlocks() << std::endl;
-//	std::cout << "wrapper residual blocks: " << id_2_residual_idx_.size() << std::endl;
-//	std::cout << "parameter blocks: " << ceres_problem_->NumParameterBlocks() << std::endl;
-
-    assert(ceres_problem_->NumResidualBlocks() == id_2_residual_idx_.size() && "ceres residuals different from wrapper residuals");
-    assert(wolf_problem_->getConstraintNotificationList().empty() && "wolf problem's constraints notification list not empty after update");
-    assert(wolf_problem_->getStateBlockNotificationList().empty() && "wolf problem's state_blocks notification list not empty after update");
+    else
+        std::cout << "WARNING: Couldn't compute covariances!" << std::endl;
 }
 
-void CeresManager::addConstraint(ConstraintBasePtr _ctr_ptr, unsigned int _id)
+void CeresManager::addConstraint(ConstraintBasePtr _ctr_ptr)
 {
-    id_2_costfunction_[_id] = createCostFunction(_ctr_ptr);
+    ctr_2_costfunction_[_ctr_ptr] = createCostFunction(_ctr_ptr);
 
-//    std::cout << "adding residual " << _ctr_ptr->id() << std::endl;
-//    std::cout << "residual pointer " << _ctr_ptr << std::endl;
+//    std::cout << "adding constraint " << _ctr_ptr->id() << std::endl;
+//    std::cout << "constraint pointer " << _ctr_ptr << std::endl;
 
     if (_ctr_ptr->getApplyLossFunction())
-        id_2_residual_idx_[_id] = ceres_problem_->AddResidualBlock(id_2_costfunction_[_id], new ceres::CauchyLoss(0.5), _ctr_ptr->getStateScalarPtrVector());
+        ctr_2_residual_idx_[_ctr_ptr] = ceres_problem_->AddResidualBlock(ctr_2_costfunction_[_ctr_ptr].get(), new ceres::CauchyLoss(0.5), _ctr_ptr->getStateScalarPtrVector());
     else
-        id_2_residual_idx_[_id] = ceres_problem_->AddResidualBlock(id_2_costfunction_[_id], NULL, _ctr_ptr->getStateScalarPtrVector());
+        ctr_2_residual_idx_[_ctr_ptr] = ceres_problem_->AddResidualBlock(ctr_2_costfunction_[_ctr_ptr].get(), NULL, _ctr_ptr->getStateScalarPtrVector());
+
+    assert(ceres_problem_->NumResidualBlocks() == ctr_2_residual_idx_.size() && "ceres residuals different from wrapper residuals");
 }
 
-void CeresManager::removeConstraint(const unsigned int& _corr_id)
+void CeresManager::removeConstraint(ConstraintBasePtr _ctr_ptr)
 {
-//    std::cout << "removing constraint " << _corr_id << std::endl;
+//  std::cout << "removing constraint " << _ctr_ptr->id() << std::endl;
 
-    assert(id_2_residual_idx_.find(_corr_id) != id_2_residual_idx_.end());
-	ceres_problem_->RemoveResidualBlock(id_2_residual_idx_[_corr_id]);
-	id_2_residual_idx_.erase(_corr_id);
+    assert(ctr_2_residual_idx_.find(_ctr_ptr) != ctr_2_residual_idx_.end());
+	ceres_problem_->RemoveResidualBlock(ctr_2_residual_idx_[_ctr_ptr]);
+	ctr_2_residual_idx_.erase(_ctr_ptr);
+	ctr_2_costfunction_.erase(_ctr_ptr);
 
 //	std::cout << "removingremoved!" << std::endl;
-	// The cost functions will be deleted by ceres_problem destructor (IT MUST HAVE THE OWNERSHIP)
+	assert(ceres_problem_->NumResidualBlocks() == ctr_2_residual_idx_.size() && "ceres residuals different from wrapper residuals");
 }
 
 void CeresManager::addStateBlock(StateBlockPtr _st_ptr)
@@ -350,25 +287,13 @@ void CeresManager::addStateBlock(StateBlockPtr _st_ptr)
 //        std::cout << "No Local Parametrization to be added" << std::endl;
         ceres_problem_->AddParameterBlock(_st_ptr->getPtr(), _st_ptr->getSize(), nullptr);
     }
-    if (_st_ptr->isFixed())
-        updateStateBlockStatus(_st_ptr);
 }
 
-void CeresManager::removeStateBlock(double* _st_ptr)
+void CeresManager::removeStateBlock(StateBlockPtr _st_ptr)
 {
     //std::cout << "Removing State Block " << _st_ptr << std::endl;
-	assert(_st_ptr != nullptr);
-    ceres_problem_->RemoveParameterBlock(_st_ptr);
-}
-
-void CeresManager::removeAllStateBlocks()
-{
-	std::vector<double*> parameter_blocks;
-
-	ceres_problem_->GetParameterBlocks(&parameter_blocks);
-
-	for (unsigned int i = 0; i< parameter_blocks.size(); i++)
-		ceres_problem_->RemoveParameterBlock(parameter_blocks[i]);
+	assert(_st_ptr);
+    ceres_problem_->RemoveParameterBlock(_st_ptr->getPtr());
 }
 
 void CeresManager::updateStateBlockStatus(StateBlockPtr _st_ptr)
@@ -380,22 +305,18 @@ void CeresManager::updateStateBlockStatus(StateBlockPtr _st_ptr)
 		ceres_problem_->SetParameterBlockVariable(_st_ptr->getPtr());
 }
 
-ceres::CostFunction* CeresManager::createCostFunction(ConstraintBasePtr _corrPtr)
+ceres::CostFunctionPtr CeresManager::createCostFunction(ConstraintBasePtr _ctr_ptr)
 {
-	assert(_corrPtr != nullptr);
-	//std::cout << "creating cost function for constraint " << _corrPtr->id() << std::endl;
-
-    // analitic jacobian
-    if (_corrPtr->getJacobianMethod() == JAC_ANALYTIC)
-        return new CostFunctionWrapper((ConstraintAnalytic*)(_corrPtr.get())); // TODO revise pointer types
+	assert(_ctr_ptr != nullptr);
+	//std::cout << "creating cost function for constraint " << _ctr_ptr->id() << std::endl;
 
-    // auto jacobian
-    else if (_corrPtr->getJacobianMethod() == JAC_AUTO)
-        return createAutoDiffCostFunction(_corrPtr, use_wolf_auto_diff_);
+    // analitic & autodiff jacobian
+    if (_ctr_ptr->getJacobianMethod() == JAC_ANALYTIC || _ctr_ptr->getJacobianMethod() == JAC_AUTO)
+        return std::make_shared<CostFunctionWrapper>(_ctr_ptr);
 
     // numeric jacobian
-    else if (_corrPtr->getJacobianMethod() == JAC_NUMERIC)
-        return createNumericDiffCostFunction(_corrPtr, use_wolf_auto_diff_);
+    else if (_ctr_ptr->getJacobianMethod() == JAC_NUMERIC)
+        return createNumericDiffCostFunction(_ctr_ptr);
 
     else
         throw std::invalid_argument( "Bad Jacobian Method!" );
diff --git a/src/ceres_wrapper/ceres_manager.h b/src/ceres_wrapper/ceres_manager.h
index 1f41da1e2bb6226f646a6d8a19b72928bb04c46b..c36144c4ed60cb8f63e840475f3e90be138efd1e 100644
--- a/src/ceres_wrapper/ceres_manager.h
+++ b/src/ceres_wrapper/ceres_manager.h
@@ -7,84 +7,71 @@
 #include "glog/logging.h"
 
 //wolf includes
+#include "solver_manager.h"
 #include "cost_function_wrapper.h"
 #include "local_parametrization_wrapper.h"
-#include "../wolf.h"
-#include "../state_block.h"
-#include "create_auto_diff_cost_function.h"
 #include "create_numeric_diff_cost_function.h"
 
-namespace wolf {
+namespace ceres {
+    typedef std::shared_ptr<CostFunction>  CostFunctionPtr;
+}
 
+namespace wolf {
 
-
-/** \brief Enumeration of covariance blocks to be computed
- *
- * Enumeration of covariance blocks to be computed
- *
- */
-typedef enum
-{
-    ALL, ///< All blocks and all cross-covariances
-    ALL_MARGINALS, ///< All marginals
-    ROBOT_LANDMARKS ///< marginals of landmarks and current robot pose plus cross covariances of current robot and all landmarks
-} CovarianceBlocksToBeComputed;
+WOLF_PTR_TYPEDEFS(CeresManager);
 
 /** \brief Ceres manager for WOLF
  *
  */
 
-class CeresManager
+class CeresManager : public SolverManager
 {
 	protected:
-		std::map<unsigned int, ceres::ResidualBlockId> id_2_residual_idx_;
-        std::map<unsigned int, ceres::CostFunction*> id_2_costfunction_;
+		std::map<ConstraintBasePtr, ceres::ResidualBlockId> ctr_2_residual_idx_;
+        std::map<ConstraintBasePtr, ceres::CostFunctionPtr> ctr_2_costfunction_;
 		ceres::Problem* ceres_problem_;
 		ceres::Solver::Options ceres_options_;
 		ceres::Covariance* covariance_;
-		ProblemPtr wolf_problem_;
-		bool use_wolf_auto_diff_;
+		ceres::Solver::Summary summary_;
 
 	public:
-        CeresManager(ProblemPtr _wolf_problem, const ceres::Solver::Options& _ceres_options = ceres::Solver::Options(), const bool _use_wolf_auto_diff = true);
+        CeresManager(ProblemPtr _wolf_problem, const ceres::Solver::Options& _ceres_options = ceres::Solver::Options());
 
 		~CeresManager();
 
-		ceres::Solver::Summary solve();
+		virtual std::string solve(const unsigned int& _report_level);
 
-		void computeCovariances(CovarianceBlocksToBeComputed _blocks = ROBOT_LANDMARKS);
+        ceres::Solver::Summary getSummary();
 
-        ceres::Solver::Options& getSolverOptions();
+        virtual void computeCovariances(CovarianceBlocksToBeComputed _blocks = ROBOT_LANDMARKS);
 
-        void setUseWolfAutoDiff(bool _use_wolf_auto_diff);
+        virtual void computeCovariances(const StateBlockList& st_list);
 
-	private:
-
-		void update();
+        ceres::Solver::Options& getSolverOptions();
 
-		void addConstraint(ConstraintBasePtr _corr_ptr, unsigned int _id);
+	private:
 
-		void removeConstraint(const unsigned int& _corr_idx);
+        virtual void addConstraint(ConstraintBasePtr _ctr_ptr);
 
-		void addStateBlock(StateBlockPtr _st_ptr);
+        virtual void removeConstraint(ConstraintBasePtr _ctr_ptr);
 
-		void removeStateBlock(double* _st_ptr);
+        virtual void addStateBlock(StateBlockPtr _st_ptr);
 
-		void removeAllStateBlocks();
+        virtual void removeStateBlock(StateBlockPtr _st_ptr);
 
-		void updateStateBlockStatus(StateBlockPtr _st_ptr);
+		virtual void updateStateBlockStatus(StateBlockPtr _st_ptr);
 
-		ceres::CostFunction* createCostFunction(ConstraintBasePtr _corrPtr);
+		ceres::CostFunctionPtr createCostFunction(ConstraintBasePtr _ctr_ptr);
 };
 
-inline ceres::Solver::Options& CeresManager::getSolverOptions()
+inline ceres::Solver::Summary CeresManager::getSummary()
 {
-    return ceres_options_;
+    return summary_;
 }
 
-inline void CeresManager::setUseWolfAutoDiff(bool _use_wolf_auto_diff)
+inline ceres::Solver::Options& CeresManager::getSolverOptions()
 {
-    use_wolf_auto_diff_ = _use_wolf_auto_diff;
+    return ceres_options_;
 }
 
 } // namespace wolf
diff --git a/src/ceres_wrapper/cost_function_wrapper.h b/src/ceres_wrapper/cost_function_wrapper.h
index 2a0a1f9d5b4ee03348b476ea3521e83303f62830..256b81703040f692323e0c647106e833b200ddd2 100644
--- a/src/ceres_wrapper/cost_function_wrapper.h
+++ b/src/ceres_wrapper/cost_function_wrapper.h
@@ -13,60 +13,32 @@
 
 namespace wolf {
 
+WOLF_PTR_TYPEDEFS(CostFunctionWrapper);
+
 class CostFunctionWrapper : public ceres::CostFunction
 {
     protected:
-        ConstraintAnalytic* constraint_ptr_;
-        std::vector<unsigned int> state_blocks_sizes_;
+        ConstraintBasePtr constraint_ptr_;
 
     public:
 
-        CostFunctionWrapper(ConstraintAnalytic* _constraint_ptr) :
+        CostFunctionWrapper(ConstraintBasePtr _constraint_ptr) :
             ceres::CostFunction(),
-            constraint_ptr_(_constraint_ptr),
-            state_blocks_sizes_(constraint_ptr_->getStateSizes())
+            constraint_ptr_(_constraint_ptr)
         {
-            for (unsigned int i = 0; i < constraint_ptr_->getStateBlockPtrVector().size(); i++)
-                mutable_parameter_block_sizes()->push_back(state_blocks_sizes_[i]);
+            for (auto st_block_size : constraint_ptr_->getStateSizes())
+                mutable_parameter_block_sizes()->push_back(st_block_size);
 
             set_num_residuals(constraint_ptr_->getSize());
         };
 
         virtual ~CostFunctionWrapper()
         {
-
         };
 
         virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
         {
-            // load parameters evaluation value
-            std::vector<Eigen::Map<const Eigen::VectorXs>> state_blocks_map_;
-            for (unsigned int i = 0; i < state_blocks_sizes_.size(); i++)
-                state_blocks_map_.push_back(Eigen::Map<const Eigen::VectorXs>((Scalar*)parameters[i], state_blocks_sizes_[i]));
-
-            // residuals
-            Eigen::Map<Eigen::VectorXs> residuals_map((Scalar*)residuals, constraint_ptr_->getSize());
-            residuals_map = constraint_ptr_->evaluateResiduals(state_blocks_map_);
-
-            // also compute jacobians
-            if (jacobians != nullptr)
-            {
-                std::vector<Eigen::Map<Eigen::MatrixXs>> jacobians_map_;
-                std::vector<bool> compute_jacobians_(state_blocks_sizes_.size());
-
-                for (unsigned int i = 0; i < state_blocks_sizes_.size(); i++)
-                {
-                    compute_jacobians_[i] = (jacobians[i] != nullptr);
-                    if (jacobians[i] != nullptr)
-                        jacobians_map_.push_back(Eigen::Map<Eigen::MatrixXs>((Scalar*)jacobians[i], constraint_ptr_->getSize(), state_blocks_sizes_[i]));
-                    else
-                        jacobians_map_.push_back(Eigen::Map<Eigen::MatrixXs>(nullptr, 0, 0)); //TODO: check if it can be done
-                }
-
-                // evaluate jacobians
-                constraint_ptr_->evaluateJacobians(state_blocks_map_, jacobians_map_, compute_jacobians_);
-            }
-            return true;
+            return constraint_ptr_->evaluate(parameters, residuals, jacobians);
         }
 };
 
diff --git a/src/ceres_wrapper/create_auto_diff_cost_function.cpp b/src/ceres_wrapper/create_auto_diff_cost_function.cpp
deleted file mode 100644
index c47c144c3fd4109363a78598ffce879e1384f397..0000000000000000000000000000000000000000
--- a/src/ceres_wrapper/create_auto_diff_cost_function.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * create_auto_diff_cost_function.cpp
- *
- *  Created on: May 18, 2016
- *      Author: jvallve
- */
-
-#include "create_auto_diff_cost_function.h"
-
-// Constraints
-#include "../constraint_sparse.h"
-#include "../constraint_fix.h"
-#include "../constraint_fix_3D.h"
-#include "../constraint_fix_bias.h"
-#include "../constraint_gps_2D.h"
-#include "../constraint_gps_pseudorange_3D.h"
-#include "../constraint_gps_pseudorange_2D.h"
-#include "../constraint_odom_2D.h"
-#include "../constraint_odom_3D.h"
-#include "../constraint_corner_2D.h"
-#include "../constraint_point_2D.h"
-#include "../constraint_point_to_line_2D.h"
-#include "../constraint_container.h"
-
-#ifdef CV_VERSION
-  #include "../constraint_AHP.h"
-#endif
-
-#include "../constraint_imu.h"
-
-// Wolf and ceres auto_diff creators
-#include "create_auto_diff_cost_function_wrapper.h"
-#include "create_auto_diff_cost_function_ceres.h"
-
-namespace wolf {
-
-ceres::CostFunction* createAutoDiffCostFunction(ConstraintBasePtr _ctr_ptr, bool _use_wolf_autodiff)
-{
-    switch (_ctr_ptr->getTypeId())
-    {
-        case CTR_GPS_FIX_2D:
-            if (_use_wolf_autodiff)
-                return createAutoDiffCostFunctionWrapper<ConstraintGPS2D>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintGPS2D>(_ctr_ptr);
-
-        case CTR_FIX:
-            if (_use_wolf_autodiff)
-                return createAutoDiffCostFunctionWrapper<ConstraintFix>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintFix>(_ctr_ptr);
-
-        case CTR_FIX_3D:
-            if (_use_wolf_autodiff)
-                return createAutoDiffCostFunctionWrapper<ConstraintFix3D>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintFix3D>(_ctr_ptr);
-
-        case CTR_FIX_BIAS:
-            if(_use_wolf_autodiff)
-                return createAutoDiffCostFunctionWrapper<ConstraintFixBias>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintFixBias>(_ctr_ptr);
-
-        case CTR_ODOM_2D:
-            if (_use_wolf_autodiff)
-                return createAutoDiffCostFunctionWrapper<ConstraintOdom2D>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintOdom2D>(_ctr_ptr);
-
-        case CTR_ODOM_3D:
-            if (_use_wolf_autodiff)
-                return createAutoDiffCostFunctionWrapper<ConstraintOdom3D>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintOdom3D>(_ctr_ptr);
-
-        case CTR_CORNER_2D:
-            if (_use_wolf_autodiff)
-                return createAutoDiffCostFunctionWrapper<ConstraintCorner2D>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintCorner2D>(_ctr_ptr);
-
-        case CTR_CONTAINER:
-            if (_use_wolf_autodiff)
-                return createAutoDiffCostFunctionWrapper<ConstraintContainer>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintContainer>(_ctr_ptr);
-
-        case CTR_GPS_PR_3D:
-            if (_use_wolf_autodiff)
-                return createAutoDiffCostFunctionWrapper<ConstraintGPSPseudorange3D>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintGPSPseudorange3D>(_ctr_ptr);
-
-        case CTR_GPS_PR_2D:
-            if (_use_wolf_autodiff)
-                return createAutoDiffCostFunctionWrapper<ConstraintGPSPseudorange2D>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintGPSPseudorange2D>(_ctr_ptr);
-
-        case CTR_POINT_2D:
-            if (_use_wolf_autodiff)
-            	return createAutoDiffCostFunctionWrapper<ConstraintPoint2D>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintPoint2D>(_ctr_ptr);
-
-        case CTR_POINT_TO_LINE_2D:
-            if (_use_wolf_autodiff)
-            	return createAutoDiffCostFunctionWrapper<ConstraintPointToLine2D>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintPointToLine2D>(_ctr_ptr);
-#ifdef CV_VERSION
-        case CTR_EPIPOLAR:
-            if (_use_wolf_autodiff)
-                return createAutoDiffCostFunctionWrapper<ConstraintAHP>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintAHP>(_ctr_ptr);
-
-        case CTR_AHP:
-            if (_use_wolf_autodiff)
-                return createAutoDiffCostFunctionWrapper<ConstraintAHP>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintAHP>(_ctr_ptr);
-#endif
-        case CTR_IMU:
-            if (_use_wolf_autodiff)
-                return createAutoDiffCostFunctionWrapper<ConstraintIMU>(_ctr_ptr);
-            else
-                return createAutoDiffCostFunctionCeres<ConstraintIMU>(_ctr_ptr);
-
-            /* For adding a new constraint, add the #include and a case:
-            case CTR_ENUM:
-                if (_use_wolf_autodiff)
-                    return createAutoDiffCostFunctionWrapper<ConstraintType>(_ctr_ptr);
-                else
-                    return createAutoDiffCostFunctionCeres<ConstraintType>(_ctr_ptr);
-             */
-
-        default:
-            throw std::invalid_argument( "Unknown constraint type! Please add it in the file: ceres_wrapper/create_auto_diff_cost_function.cpp" );
-    }
-}
-
-} // namespace wolf
diff --git a/src/ceres_wrapper/create_auto_diff_cost_function.h b/src/ceres_wrapper/create_auto_diff_cost_function.h
deleted file mode 100644
index d50bdb97fe266eaef6a19d919a7dd31605df56a7..0000000000000000000000000000000000000000
--- a/src/ceres_wrapper/create_auto_diff_cost_function.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * create_auto_diff_cost_function.h
- *
- *  Created on: Apr 4, 2016
- *      Author: jvallve
- */
-
-#ifndef SRC_CERES_WRAPPER_CREATE_AUTO_DIFF_COST_FUNCTION_H_
-#define SRC_CERES_WRAPPER_CREATE_AUTO_DIFF_COST_FUNCTION_H_
-
-#include "../constraint_base.h"
-#include "ceres/cost_function.h"
-
-namespace wolf {
-    ceres::CostFunction* createAutoDiffCostFunction(ConstraintBasePtr _ctr_ptr, bool _use_wolf_autodiff);
-
-}
-
-#endif /* SRC_CERES_WRAPPER_CREATE_AUTO_DIFF_COST_FUNCTION_H_ */
diff --git a/src/ceres_wrapper/create_auto_diff_cost_function_ceres.h b/src/ceres_wrapper/create_auto_diff_cost_function_ceres.h
deleted file mode 100644
index 3d6182a426ef1e3e5466034d7ac452f70cadde8f..0000000000000000000000000000000000000000
--- a/src/ceres_wrapper/create_auto_diff_cost_function_ceres.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * create_auto_diff_cost_function_ceres.h
- *
- *  Created on: Apr 5, 2016
- *      Author: jvallve
- */
-
-#ifndef SRC_CERES_WRAPPER_CREATE_AUTO_DIFF_COST_FUNCTION_CERES_H_
-#define SRC_CERES_WRAPPER_CREATE_AUTO_DIFF_COST_FUNCTION_CERES_H_
-
-#include "ceres/autodiff_cost_function.h"
-
-namespace wolf {
-
-template <class CtrType>
-ceres::AutoDiffCostFunction<CtrType,
-                            CtrType::residualSize,
-                            CtrType::block0Size,CtrType::block1Size,
-                            CtrType::block2Size,CtrType::block3Size,
-                            CtrType::block4Size,CtrType::block5Size,
-                            CtrType::block6Size,CtrType::block7Size,
-                            CtrType::block8Size,CtrType::block9Size>* createAutoDiffCostFunctionCeres(ConstraintBasePtr _constraint_ptr)
-{
-    static_assert(CtrType::residualSize != 0,"Measurement size cannot be null!");
-    static_assert(!(CtrType::block0Size == 0 ||
-                   (CtrType::block1Size > 0 && CtrType::block0Size == 0) ||
-                   (CtrType::block2Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0)) ||
-                   (CtrType::block3Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0)) ||
-                   (CtrType::block4Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0)) ||
-                   (CtrType::block5Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0)) ||
-                   (CtrType::block6Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0 || CtrType::block5Size == 0)) ||
-                   (CtrType::block7Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0 || CtrType::block5Size == 0 || CtrType::block6Size == 0)) ||
-                   (CtrType::block8Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0 || CtrType::block5Size == 0 || CtrType::block6Size == 0 || CtrType::block7Size == 0)) ||
-                   (CtrType::block9Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0 || CtrType::block5Size == 0 || CtrType::block6Size == 0 || CtrType::block7Size == 0 || CtrType::block8Size == 0))),
-                  "bad block sizes numbers!");
-
-    return new ceres::AutoDiffCostFunction<CtrType, CtrType::residualSize,
-                                           CtrType::block0Size,CtrType::block1Size,CtrType::block2Size,CtrType::block3Size,CtrType::block4Size,
-                                           CtrType::block5Size,CtrType::block6Size,CtrType::block7Size,CtrType::block8Size,CtrType::block9Size>(std::static_pointer_cast<CtrType>(_constraint_ptr).get()); // TODO revise pointer types
-};
-
-} // namespace wolf
-
-#endif /* SRC_CERES_WRAPPER_CREATE_AUTO_DIFF_COST_FUNCTION_CERES_H_ */
diff --git a/src/ceres_wrapper/create_auto_diff_cost_function_wrapper.h b/src/ceres_wrapper/create_auto_diff_cost_function_wrapper.h
deleted file mode 100644
index 32b3cec5212258d0bc2b1f2a184a4eaa41079fe2..0000000000000000000000000000000000000000
--- a/src/ceres_wrapper/create_auto_diff_cost_function_wrapper.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * create_auto_diff_cost_function.h
- *
- *  Created on: Apr 5, 2016
- *      Author: jvallve
- */
-
-#ifndef SRC_CERES_WRAPPER_CREATE_AUTO_DIFF_COST_FUNCTION_WRAPPER_H_
-#define SRC_CERES_WRAPPER_CREATE_AUTO_DIFF_COST_FUNCTION_WRAPPER_H_
-
-#include "auto_diff_cost_function_wrapper.h"
-
-namespace wolf {
-
-template <class CtrType>
-AutoDiffCostFunctionWrapperBase<CtrType,
-                                CtrType::residualSize,
-                                CtrType::block0Size,CtrType::block1Size,
-                                CtrType::block2Size,CtrType::block3Size,
-                                CtrType::block4Size,CtrType::block5Size,
-                                CtrType::block6Size,CtrType::block7Size,
-                                CtrType::block8Size,CtrType::block9Size>* createAutoDiffCostFunctionWrapper(ConstraintBasePtr _constraint_ptr)
-{
-    static_assert(CtrType::residualSize != 0,"Measurement size cannot be null!");
-    static_assert(!(CtrType::block0Size == 0 ||
-                   (CtrType::block1Size > 0 && CtrType::block0Size == 0) ||
-                   (CtrType::block2Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0)) ||
-                   (CtrType::block3Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0)) ||
-                   (CtrType::block4Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0)) ||
-                   (CtrType::block5Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0)) ||
-                   (CtrType::block6Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0 || CtrType::block5Size == 0)) ||
-                   (CtrType::block7Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0 || CtrType::block5Size == 0 || CtrType::block6Size == 0)) ||
-                   (CtrType::block8Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0 || CtrType::block5Size == 0 || CtrType::block6Size == 0 || CtrType::block7Size == 0)) ||
-                   (CtrType::block9Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0 || CtrType::block5Size == 0 || CtrType::block6Size == 0 || CtrType::block7Size == 0 || CtrType::block8Size == 0))),
-                  "bad block sizes numbers!");
-
-    return new AutoDiffCostFunctionWrapperBase<CtrType, CtrType::residualSize,
-                                               CtrType::block0Size,CtrType::block1Size,CtrType::block2Size,CtrType::block3Size,CtrType::block4Size,
-                                               CtrType::block5Size,CtrType::block6Size,CtrType::block7Size,CtrType::block8Size,CtrType::block9Size>(std::static_pointer_cast<CtrType>(_constraint_ptr).get()); // TODO revise pointer types
-};
-
-} // namespace wolf
-
-#endif /* SRC_CERES_WRAPPER_CREATE_AUTO_DIFF_COST_FUNCTION_WRAPPER_H_ */
diff --git a/src/ceres_wrapper/create_numeric_diff_cost_function.cpp b/src/ceres_wrapper/create_numeric_diff_cost_function.cpp
deleted file mode 100644
index cfadab44bfe16aa05bd37c6c16c51bc867f1ee7f..0000000000000000000000000000000000000000
--- a/src/ceres_wrapper/create_numeric_diff_cost_function.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * create_numerical_diff_cost_function.cpp
- *
- *  Created on: May 18, 2016
- *      Author: jvallve
- */
-
-#include "create_numeric_diff_cost_function.h"
-
-// Constraints
-#include "../constraint_odom_2D.h"
-
-// Wolf and ceres auto_diff creators
-#include "create_numeric_diff_cost_function_ceres.h"
-
-namespace wolf {
-
-ceres::CostFunction* createNumericDiffCostFunction(ConstraintBasePtr _ctr_ptr, bool _use_wolf_numericdiff)
-{
-    if (_use_wolf_numericdiff)
-        throw std::invalid_argument( "Numeric differentiation not implemented in wolf" );
-
-    switch (_ctr_ptr->getTypeId())
-    {
-        // just for testing
-        case CTR_ODOM_2D:
-            return createNumericDiffCostFunctionCeres<ConstraintOdom2D>(_ctr_ptr);
-
-        /* For adding a new constraint, add the #include and a case:
-        case CTR_ENUM:
-            return createNumericDiffCostFunctionCeres<ConstraintType>(_ctr_ptr);
-         */
-
-        default:
-            throw std::invalid_argument( "Unknown constraint type! Please add it in the file: ceres_wrapper/create_Numeric_diff_cost_function.h" );
-    }
-}
-
-} // namespace wolf
diff --git a/src/ceres_wrapper/create_numeric_diff_cost_function.h b/src/ceres_wrapper/create_numeric_diff_cost_function.h
index e53e84f966c60a97ac0d38e0160816d34deda28e..ff9d34088fb2479e63de7f19ff3806389b049969 100644
--- a/src/ceres_wrapper/create_numeric_diff_cost_function.h
+++ b/src/ceres_wrapper/create_numeric_diff_cost_function.h
@@ -1,5 +1,5 @@
 /*
- * create_numerical_diff_cost_function.h
+ * create_numeric_diff_cost_function.h
  *
  *  Created on: Apr 5, 2016
  *      Author: jvallve
@@ -9,11 +9,44 @@
 #define SRC_CERES_WRAPPER_CREATE_NUMERIC_DIFF_COST_FUNCTION_H_
 
 #include "ceres/cost_function.h"
+#include "ceres/numeric_diff_cost_function.h"
+
+// Constraints
+#include "../constraint_odom_2D.h"
 #include "../constraint_base.h"
 
+
 namespace wolf {
 
-ceres::CostFunction* createNumericDiffCostFunction(ConstraintBasePtr _ctr_ptr, bool _use_wolf_numericdiff);
+// Wolf ceres auto_diff creator
+template <class T>
+std::shared_ptr<ceres::NumericDiffCostFunction<T, ceres::CENTRAL, T::residualSize,
+                                               T::block0Size,T::block1Size,T::block2Size,T::block3Size,T::block4Size,
+                                               T::block5Size,T::block6Size,T::block7Size,T::block8Size,T::block9Size> > createNumericDiffCostFunctionCeres(ConstraintBasePtr _constraint_ptr)
+{
+    return std::make_shared<ceres::NumericDiffCostFunction<T, ceres::CENTRAL, T::residualSize,
+                                                           T::block0Size,T::block1Size,T::block2Size,T::block3Size,T::block4Size,
+                                                           T::block5Size,T::block6Size,T::block7Size,T::block8Size,T::block9Size> >(std::static_pointer_cast<T>(_constraint_ptr).get());
+};
+
+
+std::shared_ptr<ceres::CostFunction> createNumericDiffCostFunction(ConstraintBasePtr _ctr_ptr)
+{
+    switch (_ctr_ptr->getTypeId())
+    {
+        // just for testing
+        case CTR_ODOM_2D:
+            return createNumericDiffCostFunctionCeres<ConstraintOdom2D>(_ctr_ptr);
+
+        /* For adding a new constraint, add the #include and a case:
+        case CTR_ENUM:
+            return createNumericDiffCostFunctionCeres<ConstraintType>(_ctr_ptr);
+         */
+
+        default:
+            throw std::invalid_argument( "Unknown constraint type! Please add it in the file: ceres_wrapper/create_Numeric_diff_cost_function.h" );
+    }
+}
 
 } // namespace wolf
 
diff --git a/src/ceres_wrapper/create_numeric_diff_cost_function_ceres.h b/src/ceres_wrapper/create_numeric_diff_cost_function_ceres.h
deleted file mode 100644
index 88876221a5289eeba7685e430982d765e9e6b5e2..0000000000000000000000000000000000000000
--- a/src/ceres_wrapper/create_numeric_diff_cost_function_ceres.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * create_numric_cost_function_ceres.h
- *
- *  Created on: Apr 5, 2016
- *      Author: jvallve
- */
-
-#ifndef SRC_CERES_WRAPPER_CREATE_NUMERIC_DIFF_COST_FUNCTION_CERES_H_
-#define SRC_CERES_WRAPPER_CREATE_NUMERIC_DIFF_COST_FUNCTION_CERES_H_
-
-#include "ceres/numeric_diff_cost_function.h"
-
-namespace wolf {
-
-template <class CtrType>
-ceres::NumericDiffCostFunction<CtrType, ceres::CENTRAL,
-                                CtrType::residualSize,
-                                CtrType::block0Size,CtrType::block1Size,
-                                CtrType::block2Size,CtrType::block3Size,
-                                CtrType::block4Size,CtrType::block5Size,
-                                CtrType::block6Size,CtrType::block7Size,
-                                CtrType::block8Size,CtrType::block9Size>* createNumericDiffCostFunctionCeres(ConstraintBasePtr _constraint_ptr)
-{
-    static_assert(CtrType::residualSize != 0,"Measurement size cannot be null!");
-    static_assert(!(CtrType::block0Size == 0 ||
-                   (CtrType::block1Size > 0 && CtrType::block0Size == 0) ||
-                   (CtrType::block2Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0)) ||
-                   (CtrType::block3Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0)) ||
-                   (CtrType::block4Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0)) ||
-                   (CtrType::block5Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0)) ||
-                   (CtrType::block6Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0 || CtrType::block5Size == 0)) ||
-                   (CtrType::block7Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0 || CtrType::block5Size == 0 || CtrType::block6Size == 0)) ||
-                   (CtrType::block8Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0 || CtrType::block5Size == 0 || CtrType::block6Size == 0 || CtrType::block7Size == 0)) ||
-                   (CtrType::block9Size > 0 && (CtrType::block0Size == 0 || CtrType::block1Size == 0 || CtrType::block2Size == 0 || CtrType::block3Size == 0 || CtrType::block4Size == 0 || CtrType::block5Size == 0 || CtrType::block6Size == 0 || CtrType::block7Size == 0 || CtrType::block8Size == 0))),
-                  "bad block sizes numbers!");
-
-    return new ceres::NumericDiffCostFunction<CtrType, ceres::CENTRAL, CtrType::residualSize,
-                                              CtrType::block0Size,CtrType::block1Size,CtrType::block2Size,CtrType::block3Size,CtrType::block4Size,
-                                              CtrType::block5Size,CtrType::block6Size,CtrType::block7Size,CtrType::block8Size,CtrType::block9Size>(std::static_pointer_cast<CtrType>(_constraint_ptr).get()); // TODO revise pointer type
-};
-
-
-
-
-} // namespace wolf
-
-#endif /* SRC_CERES_WRAPPER_CREATE_NUMERIC_DIFF_COST_FUNCTION_CERES_H_ */
diff --git a/src/ceres_wrapper/qr_manager.cpp b/src/ceres_wrapper/qr_manager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e11b7369d8eb3176d992ddbe71ef1403838486ff
--- /dev/null
+++ b/src/ceres_wrapper/qr_manager.cpp
@@ -0,0 +1,232 @@
+/*
+ * qr_manager.cpp
+ *
+ *  Created on: Jun 7, 2017
+ *      Author: jvallve
+ */
+
+#include "qr_manager.h"
+
+namespace wolf {
+
+QRManager::QRManager(ProblemPtr _wolf_problem, const unsigned int& _N_batch) :
+        SolverManager(_wolf_problem),
+        A_(), // empty matrix
+        b_(),
+        any_state_block_removed_(false),
+        new_state_blocks_(0),
+        N_batch_(_N_batch),
+        pending_changes_(false)
+{
+    //
+}
+
+QRManager::~QRManager()
+{
+    sb_2_col_.clear();
+    ctr_2_row_.clear();
+}
+
+std::string QRManager::solve(const unsigned int& _report_level)
+{
+    // check for update notifications
+    update();
+
+    // Decomposition
+    if (!computeDecomposition())
+        return std::string("decomposition failed\n");
+
+    // Solve
+    Eigen::VectorXs x_incr = solver_.solve(-b_);
+    b_.setZero();
+
+    // update state blocks
+    for (auto sb_pair : sb_2_col_)
+        sb_pair.first->setState(sb_pair.first->getState() + x_incr.segment(sb_pair.second, sb_pair.first->getSize()));
+
+    if (_report_level == 1)
+        return std::string("Success!\n");
+    else if (_report_level == 2)
+        return std::string("Success!\n");
+
+    return std::string();
+}
+
+void QRManager::computeCovariances(CovarianceBlocksToBeComputed _blocks)
+{
+    // TODO
+}
+
+void QRManager::computeCovariances(const StateBlockList& _sb_list)
+{
+    //std::cout << "computing covariances.." << std::endl;
+    update();
+    computeDecomposition();
+
+//    std::cout << "R is " << solver_.matrixR().rows() << "x" << solver_.matrixR().cols() << std::endl;
+//    std::cout << Eigen::MatrixXs(solver_.matrixR()) << std::endl;
+
+    covariance_solver_.compute(solver_.matrixR().topRows(solver_.matrixR().cols()));
+
+    Eigen::SparseMatrix<Scalar, Eigen::ColMajor> I(A_.cols(),A_.cols());
+    I.setIdentity();
+    Eigen::SparseMatrix<Scalar, Eigen::ColMajor> iR = covariance_solver_.solve(I);
+    Eigen::MatrixXs Sigma_full = solver_.colsPermutation() * iR * iR.transpose() * solver_.colsPermutation().transpose();
+
+//    std::cout << "A' A = \n" << Eigen::MatrixXs(A_.transpose() * A_)<< std::endl;
+//    std::cout << "P iR iR' P' = \n" << Eigen::MatrixXs(P * iR * iR.transpose() * P.transpose()) << std::endl;
+//    std::cout << "Sigma * Lambda = \n" << Eigen::MatrixXs(Sigma_full * A_.transpose() * A_) << std::endl;
+//    std::cout << "Permutation: \n" << solver_.colsPermutation() << std::endl;
+//    std::cout << "Sigma = \n" << Sigma_full << std::endl;
+
+    // STORE DESIRED COVARIANCES
+    for (auto sb_row = _sb_list.begin(); sb_row != _sb_list.end(); sb_row++)
+        for (auto sb_col = sb_row; sb_col!=_sb_list.end(); sb_col++)
+        {
+            //std::cout << "cov state block " << sb_col->get() << std::endl;
+            assert(sb_2_col_.find(*sb_col) != sb_2_col_.end() && "state block not found");
+            //std::cout << "block: " << sb_2_col_[*sb_row] << "," << sb_2_col_[*sb_col] << std::endl << Sigma_full.block(sb_2_col_[*sb_row], sb_2_col_[*sb_col], (*sb_row)->getSize(), (*sb_col)->getSize()) << std::endl;
+            wolf_problem_->addCovarianceBlock(*sb_row, *sb_col, Sigma_full.block(sb_2_col_[*sb_row], sb_2_col_[*sb_col], (*sb_row)->getSize(), (*sb_col)->getSize()));
+        }
+}
+
+bool QRManager::computeDecomposition()
+{
+    if (pending_changes_)
+    {
+        // Rebuild problem
+        if (any_state_block_removed_)
+        {
+            // rebuild maps
+            unsigned int state_size = 0;
+            for (auto sb_pair : sb_2_col_)
+            {
+                sb_2_col_[sb_pair.first] = state_size;
+                state_size += sb_pair.first->getSize();
+            }
+
+            unsigned int meas_size = 0;
+            for (auto ctr_pair : ctr_2_row_)
+            {
+                ctr_2_row_[ctr_pair.first] = meas_size;
+                meas_size += ctr_pair.first->getSize();
+            }
+
+            // resize and setZero A, b
+            A_.resize(meas_size,state_size);
+            b_.resize(meas_size);
+        }
+
+        if (any_state_block_removed_ || new_state_blocks_ >= N_batch_)
+        {
+            // relinearize all constraints
+            for (auto ctr_pair : ctr_2_row_)
+                relinearizeConstraint(ctr_pair.first);
+
+            any_state_block_removed_ = false;
+            new_state_blocks_ = 0;
+        }
+
+        // Decomposition
+        solver_.compute(A_);
+        if (solver_.info() != Eigen::Success)
+            return false;
+    }
+
+    pending_changes_ = false;
+
+    return true;
+}
+
+void QRManager::addConstraint(ConstraintBasePtr _ctr_ptr)
+{
+    //std::cout << "add constraint " << _ctr_ptr->id() << std::endl;
+    assert(ctr_2_row_.find(_ctr_ptr) == ctr_2_row_.end() && "adding existing constraint");
+    ctr_2_row_[_ctr_ptr] = A_.rows();
+    A_.conservativeResize(A_.rows() + _ctr_ptr->getSize(), A_.cols());
+    b_.conservativeResize(b_.size() + _ctr_ptr->getSize());
+
+    assert(A_.rows() >= ctr_2_row_[_ctr_ptr] + _ctr_ptr->getSize() - 1 && "bad A number of rows");
+    assert(b_.rows() >= ctr_2_row_[_ctr_ptr] + _ctr_ptr->getSize() - 1 && "bad b number of rows");
+
+    relinearizeConstraint(_ctr_ptr);
+
+    pending_changes_ = true;
+}
+
+
+void QRManager::removeConstraint(ConstraintBasePtr _ctr_ptr)
+{
+    //std::cout << "remove constraint " << _ctr_ptr->id() << std::endl;
+    assert(ctr_2_row_.find(_ctr_ptr) != ctr_2_row_.end() && "removing unknown constraint");
+    eraseBlockRow(A_, ctr_2_row_[_ctr_ptr], _ctr_ptr->getSize());
+    b_.segment(ctr_2_row_[_ctr_ptr], _ctr_ptr->getSize()).setZero();
+    ctr_2_row_.erase(_ctr_ptr);
+    pending_changes_ = true;
+}
+
+void QRManager::addStateBlock(StateBlockPtr _st_ptr)
+{
+    //std::cout << "add state block " << _st_ptr.get() << std::endl;
+    assert(sb_2_col_.find(_st_ptr) == sb_2_col_.end() && "adding existing state block");
+    sb_2_col_[_st_ptr] = A_.cols();
+    A_.conservativeResize(A_.rows(), A_.cols() + _st_ptr->getSize());
+
+    new_state_blocks_++;
+    pending_changes_ = true;
+}
+
+void QRManager::removeStateBlock(StateBlockPtr _st_ptr)
+{
+    //std::cout << "remove state block " << _st_ptr.get() << std::endl;
+    assert(sb_2_col_.find(_st_ptr) != sb_2_col_.end() && "removing unknown state block");
+    eraseBlockCol(A_, sb_2_col_[_st_ptr], _st_ptr->getSize());
+
+    // flag to rebuild problem
+    any_state_block_removed_ = true;
+    // TODO: insert identity while problem is not re-built?
+
+    sb_2_col_.erase(_st_ptr);
+    pending_changes_ = true;
+}
+
+void QRManager::updateStateBlockStatus(StateBlockPtr _st_ptr)
+{
+    //std::cout << "update state block " << _st_ptr.get() << std::endl;
+    if (_st_ptr->isFixed())
+    {
+        if (sb_2_col_.find(_st_ptr) != sb_2_col_.end())
+            removeStateBlock(_st_ptr);
+    }
+    else
+        if (sb_2_col_.find(_st_ptr) == sb_2_col_.end())
+            addStateBlock(_st_ptr);
+}
+
+void QRManager::relinearizeConstraint(ConstraintBasePtr _ctr_ptr)
+{
+    // evaluate constraint
+    std::vector<const Scalar*> ctr_states_ptr;
+    for (auto sb : _ctr_ptr->getStateBlockPtrVector())
+        ctr_states_ptr.push_back(sb->getPtr());
+    Eigen::VectorXs residual(_ctr_ptr->getSize());
+    std::vector<Eigen::MatrixXs> jacobians;
+    _ctr_ptr->evaluate(ctr_states_ptr,residual,jacobians);
+
+    // Fill jacobians
+    Eigen::SparseMatrixs A_block_row(_ctr_ptr->getSize(), A_.cols());
+    for (auto i = 0; i < jacobians.size(); i++)
+        if (!_ctr_ptr->getStateBlockPtrVector()[i]->isFixed())
+        {
+            assert(sb_2_col_.find(_ctr_ptr->getStateBlockPtrVector()[i]) != sb_2_col_.end() && "constraint involving a state block not added");
+            assert(A_.cols() >= sb_2_col_[_ctr_ptr->getStateBlockPtrVector()[i]] + jacobians[i].cols() - 1 && "bad A number of cols");
+            // insert since A_block_row has just been created so it's empty for sure
+            insertSparseBlock(jacobians[i], A_block_row, 0, sb_2_col_[_ctr_ptr->getStateBlockPtrVector()[i]]);
+        }
+    assignBlockRow(A_, A_block_row, ctr_2_row_[_ctr_ptr]);
+
+    // Fill residual
+    b_.segment(ctr_2_row_[_ctr_ptr], _ctr_ptr->getSize()) = residual;
+}
+
+} /* namespace wolf */
diff --git a/src/ceres_wrapper/qr_manager.h b/src/ceres_wrapper/qr_manager.h
new file mode 100644
index 0000000000000000000000000000000000000000..ae7fae7a1fa475e7521bd94438e7e351be24d42b
--- /dev/null
+++ b/src/ceres_wrapper/qr_manager.h
@@ -0,0 +1,62 @@
+/*
+ * qr_manager.h
+ *
+ *  Created on: Jun 7, 2017
+ *      Author: jvallve
+ */
+
+#ifndef SRC_CERES_WRAPPER_QR_MANAGER_H_
+#define SRC_CERES_WRAPPER_QR_MANAGER_H_
+
+#include "solver_manager.h"
+#include "sparse_utils.h"
+
+namespace wolf
+{
+
+class QRManager : public SolverManager
+{
+    protected:
+        Eigen::SparseQR<Eigen::SparseMatrixs, Eigen::COLAMDOrdering<int>> solver_;
+        Eigen::SparseQR<Eigen::SparseMatrixs, Eigen::NaturalOrdering<int>> covariance_solver_;
+        Eigen::SparseMatrixs A_;
+        Eigen::VectorXs b_;
+        std::map<StateBlockPtr, unsigned int> sb_2_col_;
+        std::map<ConstraintBasePtr, unsigned int> ctr_2_row_;
+        bool any_state_block_removed_;
+        unsigned int new_state_blocks_;
+        unsigned int N_batch_;
+        bool pending_changes_;
+
+    public:
+
+        QRManager(ProblemPtr _wolf_problem, const unsigned int& _N_batch);
+
+        virtual ~QRManager();
+
+        virtual std::string solve(const unsigned int& _report_level);
+
+        virtual void computeCovariances(CovarianceBlocksToBeComputed _blocks = ROBOT_LANDMARKS);
+
+        virtual void computeCovariances(const StateBlockList& _sb_list);
+
+    private:
+
+        bool computeDecomposition();
+
+        virtual void addConstraint(ConstraintBasePtr _ctr_ptr);
+
+        virtual void removeConstraint(ConstraintBasePtr _ctr_ptr);
+
+        virtual void addStateBlock(StateBlockPtr _st_ptr);
+
+        virtual void removeStateBlock(StateBlockPtr _st_ptr);
+
+        virtual void updateStateBlockStatus(StateBlockPtr _st_ptr);
+
+        void relinearizeConstraint(ConstraintBasePtr _ctr_ptr);
+};
+
+} /* namespace wolf */
+
+#endif /* SRC_CERES_WRAPPER_QR_MANAGER_H_ */
diff --git a/src/ceres_wrapper/solver_manager.cpp b/src/ceres_wrapper/solver_manager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5b495d52fb23056c14cf308f8ceb8d69eade01f9
--- /dev/null
+++ b/src/ceres_wrapper/solver_manager.cpp
@@ -0,0 +1,93 @@
+#include "solver_manager.h"
+#include "../trajectory_base.h"
+#include "../map_base.h"
+#include "../landmark_base.h"
+
+namespace wolf {
+
+SolverManager::SolverManager(ProblemPtr _wolf_problem) :
+    wolf_problem_(_wolf_problem)
+{
+}
+
+SolverManager::~SolverManager()
+{
+}
+
+void SolverManager::update()
+{
+    //std::cout << "SolverManager: updating... " << std::endl;
+    //std::cout << wolf_problem_->getStateBlockNotificationList().size() << " state block notifications" << std::endl;
+    //std::cout << wolf_problem_->getConstraintNotificationList().size() << " constraint notifications" << std::endl;
+
+	// REMOVE CONSTRAINTS
+	auto ctr_notification_it = wolf_problem_->getConstraintNotificationList().begin();
+	while ( ctr_notification_it != wolf_problem_->getConstraintNotificationList().end() )
+		if (ctr_notification_it->notification_ == REMOVE)
+		{
+			removeConstraint(ctr_notification_it->constraint_ptr_);
+			ctr_notification_it = wolf_problem_->getConstraintNotificationList().erase(ctr_notification_it);
+		}
+		else
+			ctr_notification_it++;
+
+	// REMOVE STATE BLOCKS
+	auto state_notification_it = wolf_problem_->getStateBlockNotificationList().begin();
+	while ( state_notification_it != wolf_problem_->getStateBlockNotificationList().end() )
+		if (state_notification_it->notification_ == REMOVE)
+		{
+			removeStateBlock(state_notification_it->state_block_ptr_);
+			state_notification_it = wolf_problem_->getStateBlockNotificationList().erase(state_notification_it);
+		}
+		else
+			state_notification_it++;
+
+    // ADD/UPDATE STATE BLOCKS
+    while (!wolf_problem_->getStateBlockNotificationList().empty())
+    {
+        switch (wolf_problem_->getStateBlockNotificationList().front().notification_)
+        {
+            case ADD:
+            {
+                addStateBlock(wolf_problem_->getStateBlockNotificationList().front().state_block_ptr_);
+                if (wolf_problem_->getStateBlockNotificationList().front().state_block_ptr_->isFixed())
+                    updateStateBlockStatus(wolf_problem_->getStateBlockNotificationList().front().state_block_ptr_);
+                break;
+            }
+            case UPDATE:
+            {
+                updateStateBlockStatus(wolf_problem_->getStateBlockNotificationList().front().state_block_ptr_);
+                break;
+            }
+            default:
+                throw std::runtime_error("SolverManager::update: State Block notification must be ADD, UPATE or REMOVE.");
+        }
+        wolf_problem_->getStateBlockNotificationList().pop_front();
+    }
+    // ADD CONSTRAINTS
+    while (!wolf_problem_->getConstraintNotificationList().empty())
+    {
+        switch (wolf_problem_->getConstraintNotificationList().front().notification_)
+        {
+            case ADD:
+            {
+                addConstraint(wolf_problem_->getConstraintNotificationList().front().constraint_ptr_);
+                break;
+            }
+            default:
+                throw std::runtime_error("SolverManager::update: Constraint notification must be ADD or REMOVE.");
+        }
+        wolf_problem_->getConstraintNotificationList().pop_front();
+    }
+
+    assert(wolf_problem_->getConstraintNotificationList().empty() && "wolf problem's constraints notification list not empty after update");
+    assert(wolf_problem_->getStateBlockNotificationList().empty() && "wolf problem's state_blocks notification list not empty after update");
+}
+
+wolf::ProblemPtr SolverManager::getProblemPtr()
+{
+    return wolf_problem_;
+}
+
+} // namespace wolf
+
diff --git a/src/ceres_wrapper/solver_manager.h b/src/ceres_wrapper/solver_manager.h
new file mode 100644
index 0000000000000000000000000000000000000000..f7725df4ab188d0ef9f15245ff7a5dbd48a9ec91
--- /dev/null
+++ b/src/ceres_wrapper/solver_manager.h
@@ -0,0 +1,64 @@
+#ifndef SOLVER_MANAGER_H_
+#define SOLVER_MANAGER_H_
+
+//wolf includes
+#include "../wolf.h"
+#include "../state_block.h"
+#include "../constraint_base.h"
+
+namespace wolf {
+
+/** \brief Enumeration of covariance blocks to be computed
+ *
+ * Enumeration of covariance blocks to be computed
+ *
+ */
+typedef enum
+{
+    ALL, ///< All blocks and all cross-covariances
+    ALL_MARGINALS, ///< All marginals
+    ROBOT_LANDMARKS ///< marginals of landmarks and current robot pose plus cross covariances of current robot and all landmarks
+} CovarianceBlocksToBeComputed;
+
+WOLF_PTR_TYPEDEFS(SolverManager);
+
+/** \brief Solver manager for WOLF
+ *
+ */
+
+class SolverManager
+{
+	protected:
+		ProblemPtr wolf_problem_;
+
+	public:
+        SolverManager(ProblemPtr _wolf_problem);
+
+		virtual ~SolverManager();
+
+		virtual std::string solve(const unsigned int& _report_level) = 0;
+
+		virtual void computeCovariances(CovarianceBlocksToBeComputed _blocks = ROBOT_LANDMARKS) = 0;
+
+		virtual void computeCovariances(const StateBlockList& st_list) = 0;
+
+		virtual void update();
+
+        virtual ProblemPtr getProblemPtr();
+
+	private:
+
+		virtual void addConstraint(ConstraintBasePtr _ctr_ptr) = 0;
+
+		virtual void removeConstraint(ConstraintBasePtr _ctr_ptr) = 0;
+
+		virtual void addStateBlock(StateBlockPtr _st_ptr) = 0;
+
+		virtual void removeStateBlock(StateBlockPtr _st_ptr) = 0;
+
+		virtual void updateStateBlockStatus(StateBlockPtr _st_ptr) = 0;
+};
+
+} // namespace wolf
+
+#endif
diff --git a/src/ceres_wrapper/sparse_utils.h b/src/ceres_wrapper/sparse_utils.h
new file mode 100644
index 0000000000000000000000000000000000000000..66f49b9c8f868e84f4223408ef6f85980e89bf1b
--- /dev/null
+++ b/src/ceres_wrapper/sparse_utils.h
@@ -0,0 +1,107 @@
+/*
+ * sparse_utils.h
+ *
+ *  Created on: Jul 2, 2015
+ *      Author: jvallve
+ */
+
+#ifndef SPARSE_UTILS_H_
+#define SPARSE_UTILS_H_
+
+// eigen includes
+//#include <eigen3/Eigen/Sparse>
+
+namespace wolf
+{
+
+void eraseBlockRow(Eigen::SparseMatrix<Scalar, Eigen::RowMajor>& A, const unsigned int& _row, const unsigned int& _n_rows)
+{
+    A.middleRows(_row,_n_rows) = Eigen::SparseMatrixs(_n_rows,A.cols());
+    A.makeCompressed();
+}
+
+void eraseBlockRow(Eigen::SparseMatrix<Scalar, Eigen::ColMajor>& A, const unsigned int& _row, const unsigned int& _n_rows)
+{
+    A.prune([&](int i, int, Scalar) { return i >= _row && i < _row + _n_rows; });
+    A.makeCompressed();
+}
+
+void eraseBlockCol(Eigen::SparseMatrix<Scalar, Eigen::ColMajor>& A, const unsigned int& _col, const unsigned int& _n_cols)
+{
+    A.middleCols(_col,_n_cols) = Eigen::SparseMatrixs(A.rows(),_n_cols);
+    A.makeCompressed();
+}
+
+void eraseBlockCol(Eigen::SparseMatrix<Scalar, Eigen::RowMajor>& A, const unsigned int& _col, const unsigned int& _n_cols)
+{
+    A.prune([&](int, int j, Scalar) { return j >= _col && j < _col + _n_cols; });
+    A.makeCompressed();
+}
+
+template<int _Options, typename _StorageIndex>
+void assignSparseBlock(const Eigen::MatrixXs& ins, Eigen::SparseMatrix<Scalar,_Options,_StorageIndex>& original, const unsigned int& row, const unsigned int& col)
+{
+    for (auto ins_row = 0; ins_row < ins.rows(); ins_row++)
+        for (auto ins_col = 0; ins_col < ins.cols(); ins_col++)
+            original.coeffRef(row+ins_row, col+ins_col) = ins(ins_row,ins_col);
+
+    original.makeCompressed();
+}
+
+template<int _Options, typename _StorageIndex>
+void addSparseBlock(const Eigen::MatrixXs& ins, Eigen::SparseMatrix<Scalar,_Options,_StorageIndex>& original, const unsigned int& row, const unsigned int& col)
+{
+    for (auto ins_row = 0; ins_row < ins.rows(); ins_row++)
+        for (auto ins_col = 0; ins_col < ins.cols(); ins_col++)
+            original.coeffRef(row+ins_row, col+ins_col) += ins(ins_row,ins_col);
+
+    original.makeCompressed();
+}
+
+template<int _Options, typename _StorageIndex>
+void insertSparseBlock(const Eigen::MatrixXs& ins, Eigen::SparseMatrix<Scalar,_Options,_StorageIndex>& original, const unsigned int& row, const unsigned int& col)
+{
+    for (auto ins_row = 0; ins_row < ins.rows(); ins_row++)
+        for (auto ins_col = 0; ins_col < ins.cols(); ins_col++)
+            original.insert(row+ins_row, col+ins_col) = ins(ins_row,ins_col);
+
+    original.makeCompressed();
+}
+
+void assignBlockRow(Eigen::SparseMatrix<Scalar, Eigen::RowMajor>& A, const Eigen::SparseMatrix<Scalar, Eigen::RowMajor>& ins, const unsigned int& _row)
+{
+    assert(A.rows() >= _row + ins.rows() && A.cols() == ins.cols());
+    A.middleRows(_row, ins.rows()) = ins;
+    A.makeCompressed();
+}
+
+Eigen::SparseMatrixs createBlockDiagonal(const std::vector<Eigen::MatrixXs>& _diag_blocs)
+{
+    unsigned int dim = _diag_blocs.front().rows();
+    unsigned int size = dim * _diag_blocs.size();
+
+    Eigen::SparseMatrixs M(size,size);
+
+    unsigned int pos = 0;
+    for (const Eigen::MatrixXs& omega_k : _diag_blocs)
+    {
+        insertSparseBlock(omega_k, M, pos, pos);
+        pos += dim;
+    }
+
+    M.makeCompressed();
+
+    return M;
+}
+
+template<int _Options, typename _StorageIndex>
+void getDiagonalBlocks(const Eigen::SparseMatrix<Scalar,_Options,_StorageIndex>& _M, std::vector<Eigen::MatrixXs>& diag_, const unsigned int& dim)
+{
+    assert(_M.rows() % dim == 0 && "number of rows must be multiple of dimension");
+    diag_.clear();
+    for (auto i = 0; i < _M.rows(); i += dim)
+        diag_.push_back(Eigen::MatrixXs(_M.block(i,i,dim,dim)));
+}
+
+} // namespace wolf
+#endif /* SPARSE_UTILS_H_ */
diff --git a/src/constraint_AHP.h b/src/constraint_AHP.h
index f39c097b196d40a70d1151af5b7ff256c7d6850c..9af047fad2470d19fce4eb42adfc3d2f66bc1745 100644
--- a/src/constraint_AHP.h
+++ b/src/constraint_AHP.h
@@ -2,7 +2,7 @@
 #define CONSTRAINT_AHP_H
 
 //Wolf includes
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 #include "landmark_AHP.h"
 #include "sensor_camera.h"
 #include "pinholeTools.h"
@@ -15,7 +15,7 @@ namespace wolf {
 WOLF_PTR_TYPEDEFS(ConstraintAHP);
     
 //class    
-class ConstraintAHP : public ConstraintSparse<2, 3, 4, 3, 4, 4>
+class ConstraintAHP : public ConstraintAutodiff<ConstraintAHP, 2, 3, 4, 3, 4, 4>
 {
     protected:
         Eigen::Vector3s anchor_sensor_extrinsics_p_;
@@ -70,7 +70,7 @@ inline ConstraintAHP::ConstraintAHP(const FeatureBasePtr&   _ftr_ptr,
                                     const ProcessorBasePtr& _processor_ptr,
                                     bool             _apply_loss_function,
                                     ConstraintStatus _status) :
-        ConstraintSparse<2, 3, 4, 3, 4, 4>(CTR_AHP,
+        ConstraintAutodiff<ConstraintAHP, 2, 3, 4, 3, 4, 4>(CTR_AHP,
                                            _landmark_ptr->getAnchorFrame(),
                                            nullptr,
                                            _landmark_ptr,
diff --git a/src/constraint_analytic.cpp b/src/constraint_analytic.cpp
index 87714278a757ecf03bcad1cebfb21a3f7f35472d..9fc6a2f8187d871bf9501e8ba583ce942ce5e42d 100644
--- a/src/constraint_analytic.cpp
+++ b/src/constraint_analytic.cpp
@@ -47,103 +47,19 @@ ConstraintAnalytic::ConstraintAnalytic(ConstraintType _tp, const LandmarkBasePtr
     resizeVectors();
 }
 
-const std::vector<Scalar*> ConstraintAnalytic::getStateScalarPtrVector()
+std::vector<Scalar*> ConstraintAnalytic::getStateScalarPtrVector() const
 {
     assert(state_ptr_vector_.size() > 0 && state_ptr_vector_.size() <= 10 && "Wrong state vector size in constraint, it should be between 1 and 10");
 
-    switch (state_ptr_vector_.size())
-    {
-        case 1:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr()});
-        }
-        case 2:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr()});
-        }
-        case 3:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr()});
-        }
-        case 4:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr()});
-        }
-        case 5:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr(),
-                                             state_ptr_vector_[4]->getPtr()});
-        }
-        case 6:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr(),
-                                             state_ptr_vector_[4]->getPtr(),
-                                             state_ptr_vector_[5]->getPtr()});
-        }
-        case 7:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr(),
-                                             state_ptr_vector_[4]->getPtr(),
-                                             state_ptr_vector_[5]->getPtr(),
-                                             state_ptr_vector_[6]->getPtr()});
-        }
-        case 8:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr(),
-                                             state_ptr_vector_[4]->getPtr(),
-                                             state_ptr_vector_[5]->getPtr(),
-                                             state_ptr_vector_[6]->getPtr(),
-                                             state_ptr_vector_[7]->getPtr()});
-        }
-        case 9:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr(),
-                                             state_ptr_vector_[4]->getPtr(),
-                                             state_ptr_vector_[5]->getPtr(),
-                                             state_ptr_vector_[6]->getPtr(),
-                                             state_ptr_vector_[7]->getPtr(),
-                                             state_ptr_vector_[8]->getPtr()});
-        }
-        case 10:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr(),
-                                             state_ptr_vector_[4]->getPtr(),
-                                             state_ptr_vector_[5]->getPtr(),
-                                             state_ptr_vector_[6]->getPtr(),
-                                             state_ptr_vector_[7]->getPtr(),
-                                             state_ptr_vector_[8]->getPtr(),
-                                             state_ptr_vector_[9]->getPtr()});
-        }
-    }
+    std::vector<Scalar*> state_scalar_ptr_vector(state_ptr_vector_.size());
+
+    for (auto i = 0; i < state_scalar_ptr_vector.size(); i++)
+        state_scalar_ptr_vector[i] = state_ptr_vector_[i]->getPtr();
 
-    return std::vector<Scalar*>(0); //Not going to happen
+    return state_scalar_ptr_vector;
 }
 
-const std::vector<StateBlockPtr> ConstraintAnalytic::getStateBlockPtrVector() const
+std::vector<StateBlockPtr> ConstraintAnalytic::getStateBlockPtrVector() const
 {
     return state_ptr_vector_;
 }
diff --git a/src/constraint_analytic.h b/src/constraint_analytic.h
index 6c9ddc7f95ea104c93a9383f4425e0d159fcf8d0..279394b652498a4001579516e507159bd6fa3205 100644
--- a/src/constraint_analytic.h
+++ b/src/constraint_analytic.h
@@ -103,21 +103,21 @@ class ConstraintAnalytic: public ConstraintBase
          * Returns a vector of pointers to the state blocks in which this constraint depends
          *
          **/
-        virtual const std::vector<Scalar*> getStateScalarPtrVector() override;
+        virtual std::vector<Scalar*> getStateScalarPtrVector() const override;
 
         /** \brief Returns a vector of pointers to the states
          *
          * Returns a vector of pointers to the state in which this constraint depends
          *
          **/
-        virtual const std::vector<StateBlockPtr> getStateBlockPtrVector() const override;
+        virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const override;
 
         /** \brief Returns a vector of sizes of the state blocks
          *
          * Returns a vector of sizes of the state blocks
          *
          **/
-        virtual std::vector<unsigned int> getStateSizes() const;
+        virtual std::vector<unsigned int> getStateSizes() const override;
 
         /** \brief Returns the constraint residual size
          *
@@ -126,6 +126,50 @@ class ConstraintAnalytic: public ConstraintBase
          **/
 //        virtual unsigned int getSize() const = 0;
 
+        /** \brief Evaluate the constraint given the input parameters and returning the residuals and jacobians
+        **/
+        // TODO
+        virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const
+        {
+            // load parameters evaluation value
+            std::vector<Eigen::Map<const Eigen::VectorXs>> state_blocks_map_;
+            for (unsigned int i = 0; i < state_block_sizes_vector_.size(); i++)
+                state_blocks_map_.push_back(Eigen::Map<const Eigen::VectorXs>((Scalar*)parameters[i], state_block_sizes_vector_[i]));
+
+            // residuals
+            Eigen::Map<Eigen::VectorXs> residuals_map((Scalar*)residuals, getSize());
+            residuals_map = evaluateResiduals(state_blocks_map_);
+
+            // also compute jacobians
+            if (jacobians != nullptr)
+            {
+                std::vector<Eigen::Map<Eigen::MatrixXs>> jacobians_map_;
+                std::vector<bool> compute_jacobians_(state_block_sizes_vector_.size());
+
+                for (unsigned int i = 0; i < state_block_sizes_vector_.size(); i++)
+                {
+                    compute_jacobians_[i] = (jacobians[i] != nullptr);
+                    if (jacobians[i] != nullptr)
+                        jacobians_map_.push_back(Eigen::Map<Eigen::MatrixXs>((Scalar*)jacobians[i], getSize(), state_block_sizes_vector_[i]));
+                    else
+                        jacobians_map_.push_back(Eigen::Map<Eigen::MatrixXs>(nullptr, 0, 0)); //TODO: check if it can be done
+                }
+
+                // evaluate jacobians
+                evaluateJacobians(state_blocks_map_, jacobians_map_, compute_jacobians_);
+            }
+            return true;
+
+            return true;
+        };
+
+        /** Returns the residual vetor and a vector of Jacobian matrix corresponding to each state block evaluated in the point provided in _states_ptr
+         **/
+        // TODO
+        virtual void evaluate(const std::vector<const Scalar*>& _states_ptr, Eigen::VectorXs& residual_, std::vector<Eigen::MatrixXs>& jacobians_) const
+        {
+        };
+
         /** \brief Returns the residual evaluated in the states provided
          *
          * Returns the residual evaluated in the states provided in std::vector of mapped Eigen::VectorXs
diff --git a/src/constraint_autodiff.h b/src/constraint_autodiff.h
new file mode 100644
index 0000000000000000000000000000000000000000..3e00d4d4c7a2d8a365ca2516c90d1025c14b5004
--- /dev/null
+++ b/src/constraint_autodiff.h
@@ -0,0 +1,2392 @@
+
+#ifndef CONSTRAINT_AUTODIFF_H_
+#define CONSTRAINT_AUTODIFF_H_
+
+//Wolf includes
+#include "constraint_base.h"
+#include "state_block.h"
+
+// CERES
+#include "ceres/jet.h"
+
+// GENERAL
+#include <array>
+
+namespace wolf {
+
+//template class ConstraintAutodiff
+template <class CtrT, unsigned int RES, unsigned int B0, unsigned int B1 = 0, unsigned int B2 = 0, unsigned int B3 = 0, unsigned int B4 = 0, unsigned int B5 = 0, unsigned int B6 = 0, unsigned int B7 = 0, unsigned int B8 = 0, unsigned int B9 = 0>
+class ConstraintAutodiff: public ConstraintBase
+{
+    public:
+
+        static const unsigned int residualSize = RES;
+        static const unsigned int block0Size = B0;
+        static const unsigned int block1Size = B1;
+        static const unsigned int block2Size = B2;
+        static const unsigned int block3Size = B3;
+        static const unsigned int block4Size = B4;
+        static const unsigned int block5Size = B5;
+        static const unsigned int block6Size = B6;
+        static const unsigned int block7Size = B7;
+        static const unsigned int block8Size = B8;
+        static const unsigned int block9Size = B9;
+        static const unsigned int n_blocks = 10;
+
+        static const std::vector<unsigned int> state_block_sizes_;
+
+        typedef ceres::Jet<Scalar, B0 + B1 + B2 + B3 + B4 +
+                                   B5 + B6 + B7 + B8 + B9> WolfJet;
+
+    protected:
+
+        std::vector<StateBlockPtr> state_ptrs_;
+
+        static const std::vector<unsigned int> jacobian_locations_;
+        std::array<WolfJet, RES>* residuals_jets_;
+        std::array<WolfJet, B0>* jets_0_;
+        std::array<WolfJet, B1>* jets_1_;
+        std::array<WolfJet, B2>* jets_2_;
+        std::array<WolfJet, B3>* jets_3_;
+        std::array<WolfJet, B4>* jets_4_;
+        std::array<WolfJet, B5>* jets_5_;
+        std::array<WolfJet, B6>* jets_6_;
+        std::array<WolfJet, B7>* jets_7_;
+        std::array<WolfJet, B8>* jets_8_;
+        std::array<WolfJet, B9>* jets_9_;
+
+    public:
+        /** \brief Constructor valid for all categories (ABSOLUTE, FRAME, FEATURE, LANDMARK)
+         **/
+        ConstraintAutodiff(ConstraintType _tp,
+                           const FrameBasePtr& _frame_other_ptr,
+                           const FeatureBasePtr& _feature_other_ptr,
+                           const LandmarkBasePtr& _landmark_other_ptr,
+                           const ProcessorBasePtr& _processor_ptr,
+                           bool _apply_loss_function,
+                           ConstraintStatus _status,
+                           StateBlockPtr _state0Ptr,
+                           StateBlockPtr _state1Ptr,
+                           StateBlockPtr _state2Ptr,
+                           StateBlockPtr _state3Ptr,
+                           StateBlockPtr _state4Ptr,
+                           StateBlockPtr _state5Ptr,
+                           StateBlockPtr _state6Ptr,
+                           StateBlockPtr _state7Ptr,
+                           StateBlockPtr _state8Ptr,
+                           StateBlockPtr _state9Ptr) :
+            ConstraintBase(_tp, _frame_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status),
+            state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr,_state9Ptr}),
+            residuals_jets_(new std::array<WolfJet, RES>),
+            jets_0_(new std::array<WolfJet, B0>),
+            jets_1_(new std::array<WolfJet, B1>),
+            jets_2_(new std::array<WolfJet, B2>),
+            jets_3_(new std::array<WolfJet, B3>),
+            jets_4_(new std::array<WolfJet, B4>),
+            jets_5_(new std::array<WolfJet, B5>),
+            jets_6_(new std::array<WolfJet, B6>),
+            jets_7_(new std::array<WolfJet, B7>),
+            jets_8_(new std::array<WolfJet, B8>),
+            jets_9_(new std::array<WolfJet, B9>)
+        {
+            // initialize jets
+            unsigned int last_jet_idx = 0;
+            for (auto i = 0; i < B0; i++)
+               (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
+            for (auto i = 0; i < B1; i++)
+               (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
+            for (auto i = 0; i < B2; i++)
+               (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
+            for (auto i = 0; i < B3; i++)
+               (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
+            for (auto i = 0; i < B4; i++)
+               (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
+            for (auto i = 0; i < B5; i++)
+               (*jets_5_)[i] = WolfJet(0, last_jet_idx++);
+            for (auto i = 0; i < B6; i++)
+               (*jets_6_)[i] = WolfJet(0, last_jet_idx++);
+            for (auto i = 0; i < B7; i++)
+               (*jets_7_)[i] = WolfJet(0, last_jet_idx++);
+            for (auto i = 0; i < B8; i++)
+               (*jets_8_)[i] = WolfJet(0, last_jet_idx++);
+            for (auto i = 0; i < B9; i++)
+                (*jets_9_)[i] = WolfJet(0, last_jet_idx++);
+        }
+
+        virtual ~ConstraintAutodiff()
+        {
+            delete jets_0_;
+            delete jets_1_;
+            delete jets_2_;
+            delete jets_3_;
+            delete jets_4_;
+            delete jets_5_;
+            delete jets_6_;
+            delete jets_7_;
+            delete jets_8_;
+            delete jets_9_;
+            delete residuals_jets_;
+        }
+
+        virtual JacobianMethod getJacobianMethod() const
+        {
+            return JAC_AUTO;
+        }
+
+        /** \brief Returns the residual and jacobians given the state values
+         *
+         * Returns the residual and jacobians given the state values
+         *
+         **/
+        virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const
+        {
+            // only residuals
+            if (jacobians == nullptr)
+            {
+                (*static_cast<CtrT const*>(this))(parameters[0],
+                                                  parameters[1],
+                                                  parameters[2],
+                                                  parameters[3],
+                                                  parameters[4],
+                                                  parameters[5],
+                                                  parameters[6],
+                                                  parameters[7],
+                                                  parameters[8],
+                                                  parameters[9],
+                                                  residuals);
+            }
+            // also compute jacobians
+            else
+            {
+                // update jets real part
+                std::vector<double const*> param_vec;
+                param_vec.assign(parameters,parameters+n_blocks);
+                updateJetsRealPart(param_vec);
+
+                // call functor
+                (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                                  jets_1_->data(),
+                                                  jets_2_->data(),
+                                                  jets_3_->data(),
+                                                  jets_4_->data(),
+                                                  jets_5_->data(),
+                                                  jets_6_->data(),
+                                                  jets_7_->data(),
+                                                  jets_8_->data(),
+                                                  jets_9_->data(),
+                                                  residuals_jets_->data());
+
+                // fill the residual array
+                for (auto i = 0; i < RES; i++)
+                    residuals[i] = (*residuals_jets_)[i].a;
+
+                // fill the jacobian matrices
+                for (auto i = 0; i<n_blocks; i++)
+                    if (jacobians[i] != nullptr)
+                        for (unsigned int row = 0; row < RES; row++)
+                            std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                      (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                      jacobians[i] + row * state_block_sizes_.at(i));
+            }
+            return true;
+        }
+
+        /** \brief Updates all jets real part with values of parameters
+         *
+         **/
+        void updateJetsRealPart(const std::vector<double const*>& parameters) const
+        {
+            // update jets real part
+            for (auto i = 0; i < B0; i++)
+                (*jets_0_)[i].a = parameters[0][i];
+            for (auto i = 0; i < B1; i++)
+                (*jets_1_)[i].a = parameters[1][i];
+            for (auto i = 0; i < B2; i++)
+                (*jets_2_)[i].a = parameters[2][i];
+            for (auto i = 0; i < B3; i++)
+                (*jets_3_)[i].a = parameters[3][i];
+            for (auto i = 0; i < B4; i++)
+                (*jets_4_)[i].a = parameters[4][i];
+            for (auto i = 0; i < B5; i++)
+                (*jets_5_)[i].a = parameters[5][i];
+            for (auto i = 0; i < B6; i++)
+                (*jets_6_)[i].a = parameters[6][i];
+            for (auto i = 0; i < B7; i++)
+                (*jets_7_)[i].a = parameters[7][i];
+            for (auto i = 0; i < B8; i++)
+                (*jets_8_)[i].a = parameters[8][i];
+            for (auto i = 0; i < B9; i++)
+                (*jets_9_)[i].a = parameters[9][i];
+        }
+
+        /** \brief Returns a vector of Jacobian matrix corresponding to each state block evaluated in the point provided in _states_ptr
+         *
+         **/
+        virtual void evaluate(const std::vector<const Scalar*>& _states_ptr, Eigen::VectorXs& residual_, std::vector<Eigen::MatrixXs>& jacobians_) const
+        {
+            assert(residual_.size() == RES);
+            jacobians_.clear();
+
+            assert(_states_ptr.size() == n_blocks);
+
+            // init jacobian
+            for(auto i = 0; i < n_blocks; ++i)
+            {
+               Eigen::MatrixXs Ji = Eigen::MatrixXs::Zero(RES, state_block_sizes_[i]);
+               jacobians_.push_back(Ji);
+            }
+
+            // update jets real part
+            updateJetsRealPart(_states_ptr);
+
+            // call functor
+            (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                              jets_1_->data(),
+                                              jets_2_->data(),
+                                              jets_3_->data(),
+                                              jets_4_->data(),
+                                              jets_5_->data(),
+                                              jets_6_->data(),
+                                              jets_7_->data(),
+                                              jets_8_->data(),
+                                              jets_9_->data(),
+                                              residuals_jets_->data());
+
+            // fill the residual vector
+            for (auto i = 0; i < RES; i++)
+                residual_(i) = (*residuals_jets_)[i].a;
+
+            // fill the jacobian matrices
+            for (auto i = 0; i<n_blocks; i++)
+                if (!state_ptrs_[i]->isFixed())
+                    for (unsigned int row = 0; row < RES; row++)
+                        std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                  (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                  jacobians_[i].data() + row * state_block_sizes_.at(i));
+
+           // print jacobian matrices
+//           for (auto i = 0; i < n_blocks; i++)
+//               std::cout << jacobians_[i] << std::endl << std::endl;
+        }
+
+        /** \brief Returns a vector of pointers to the state blocks
+         *
+         * Returns a vector of pointers to the state blocks in which this constraint depends
+         *
+         **/
+        virtual std::vector<Scalar*> getStateScalarPtrVector() const
+        {
+            return std::vector<Scalar*>({state_ptrs_[0]->getPtr(),
+                                         state_ptrs_[1]->getPtr(),
+                                         state_ptrs_[2]->getPtr(),
+                                         state_ptrs_[3]->getPtr(),
+                                         state_ptrs_[4]->getPtr(),
+                                         state_ptrs_[5]->getPtr(),
+                                         state_ptrs_[6]->getPtr(),
+                                         state_ptrs_[7]->getPtr(),
+                                         state_ptrs_[8]->getPtr(),
+                                         state_ptrs_[9]->getPtr()
+                                         });
+        }
+
+        /** \brief Returns a vector of pointers to the states
+         *
+         * Returns a vector of pointers to the state in which this constraint depends
+         *
+         **/
+        virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const
+        {
+            return state_ptrs_;
+        }
+
+        /** \brief Returns a vector of the states sizes
+         *
+         **/
+        virtual std::vector<unsigned int> getStateSizes() const
+        {
+            return state_block_sizes_;
+        }
+
+        /** \brief Returns the residual size
+         *
+         * Returns the residual size
+         *
+         **/
+        virtual unsigned int getSize() const
+        {
+            return RES;
+        }
+};
+
+
+////////////////// SPECIALIZATION 9 BLOCKS ////////////////////////////////////////////////////////////////////////
+
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8>
+class ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0> : public ConstraintBase
+{
+   public:
+
+       static const unsigned int residualSize = RES;
+       static const unsigned int block0Size = B0;
+       static const unsigned int block1Size = B1;
+       static const unsigned int block2Size = B2;
+       static const unsigned int block3Size = B3;
+       static const unsigned int block4Size = B4;
+       static const unsigned int block5Size = B5;
+       static const unsigned int block6Size = B6;
+       static const unsigned int block7Size = B7;
+       static const unsigned int block8Size = B8;
+       static const unsigned int block9Size = 0;
+       static const unsigned int n_blocks = 9;
+
+       static const std::vector<unsigned int> state_block_sizes_;
+
+       typedef ceres::Jet<Scalar, B0 + B1 + B2 + B3 + B4 +
+                                  B5 + B6 + B7 + B8> WolfJet;
+
+   protected:
+
+       std::vector<StateBlockPtr> state_ptrs_;
+
+       static const std::vector<unsigned int> jacobian_locations_;
+       std::array<WolfJet, RES>* residuals_jets_;
+
+       std::array<WolfJet, B0>* jets_0_;
+       std::array<WolfJet, B1>* jets_1_;
+       std::array<WolfJet, B2>* jets_2_;
+       std::array<WolfJet, B3>* jets_3_;
+       std::array<WolfJet, B4>* jets_4_;
+       std::array<WolfJet, B5>* jets_5_;
+       std::array<WolfJet, B6>* jets_6_;
+       std::array<WolfJet, B7>* jets_7_;
+       std::array<WolfJet, B8>* jets_8_;
+
+   public:
+
+       ConstraintAutodiff(ConstraintType _tp,
+                          const FrameBasePtr& _frame_other_ptr,
+                          const FeatureBasePtr& _feature_other_ptr,
+                          const LandmarkBasePtr& _landmark_other_ptr,
+                          const ProcessorBasePtr& _processor_ptr,
+                          bool _apply_loss_function,
+                          ConstraintStatus _status,
+                          StateBlockPtr _state0Ptr,
+                          StateBlockPtr _state1Ptr,
+                          StateBlockPtr _state2Ptr,
+                          StateBlockPtr _state3Ptr,
+                          StateBlockPtr _state4Ptr,
+                          StateBlockPtr _state5Ptr,
+                          StateBlockPtr _state6Ptr,
+                          StateBlockPtr _state7Ptr,
+                          StateBlockPtr _state8Ptr) :
+           ConstraintBase(_tp, _frame_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status),
+           state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr}),
+           residuals_jets_(new std::array<WolfJet, RES>),
+           jets_0_(new std::array<WolfJet, B0>),
+           jets_1_(new std::array<WolfJet, B1>),
+           jets_2_(new std::array<WolfJet, B2>),
+           jets_3_(new std::array<WolfJet, B3>),
+           jets_4_(new std::array<WolfJet, B4>),
+           jets_5_(new std::array<WolfJet, B5>),
+           jets_6_(new std::array<WolfJet, B6>),
+           jets_7_(new std::array<WolfJet, B7>),
+           jets_8_(new std::array<WolfJet, B8>)
+       {
+           // initialize jets
+           unsigned int last_jet_idx = 0;
+           for (auto i = 0; i < B0; i++)
+              (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B1; i++)
+              (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B2; i++)
+              (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B3; i++)
+              (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B4; i++)
+              (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B5; i++)
+              (*jets_5_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B6; i++)
+              (*jets_6_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B7; i++)
+              (*jets_7_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B8; i++)
+              (*jets_8_)[i] = WolfJet(0, last_jet_idx++);
+           state_ptrs_.resize(n_blocks);
+       }
+
+       virtual ~ConstraintAutodiff()
+       {
+           delete jets_0_;
+           delete jets_1_;
+           delete jets_2_;
+           delete jets_3_;
+           delete jets_4_;
+           delete jets_5_;
+           delete jets_6_;
+           delete jets_7_;
+           delete jets_8_;
+           delete residuals_jets_;
+       }
+
+       virtual JacobianMethod getJacobianMethod() const
+       {
+           return JAC_AUTO;
+       }
+
+       virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const
+       {
+           // only residuals
+           if (jacobians == nullptr)
+           {
+               (*static_cast<CtrT const*>(this))(parameters[0],
+                                                        parameters[1],
+                                                        parameters[2],
+                                                        parameters[3],
+                                                        parameters[4],
+                                                        parameters[5],
+                                                        parameters[6],
+                                                        parameters[7],
+                                                        parameters[8],
+                                                        residuals);
+           }
+           // also compute jacobians
+           else
+           {
+               // update jets real part
+               std::vector<double const*> param_vec;
+               param_vec.assign(parameters,parameters+n_blocks);
+               updateJetsRealPart(param_vec);
+
+               // call functor
+               (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                                        jets_1_->data(),
+                                                        jets_2_->data(),
+                                                        jets_3_->data(),
+                                                        jets_4_->data(),
+                                                        jets_5_->data(),
+                                                        jets_6_->data(),
+                                                        jets_7_->data(),
+                                                        jets_8_->data(),
+                                                        residuals_jets_->data());
+
+               // fill the residual array
+               for (auto i = 0; i < RES; i++)
+                   residuals[i] = (*residuals_jets_)[i].a;
+
+               // fill the jacobian matrices
+               for (auto i = 0; i<n_blocks; i++)
+                   if (jacobians[i] != nullptr)
+                       for (unsigned int row = 0; row < RES; row++)
+                           std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                     (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                     jacobians[i] + row * state_block_sizes_.at(i));
+           }
+           return true;
+       }
+
+       void updateJetsRealPart(const std::vector<double const*>& parameters) const
+       {
+           // update jets real part
+           for (auto i = 0; i < B0; i++)
+               (*jets_0_)[i].a = parameters[0][i];
+           for (auto i = 0; i < B1; i++)
+               (*jets_1_)[i].a = parameters[1][i];
+           for (auto i = 0; i < B2; i++)
+               (*jets_2_)[i].a = parameters[2][i];
+           for (auto i = 0; i < B3; i++)
+               (*jets_3_)[i].a = parameters[3][i];
+           for (auto i = 0; i < B4; i++)
+               (*jets_4_)[i].a = parameters[4][i];
+           for (auto i = 0; i < B5; i++)
+               (*jets_5_)[i].a = parameters[5][i];
+           for (auto i = 0; i < B6; i++)
+               (*jets_6_)[i].a = parameters[6][i];
+           for (auto i = 0; i < B7; i++)
+               (*jets_7_)[i].a = parameters[7][i];
+           for (auto i = 0; i < B8; i++)
+               (*jets_8_)[i].a = parameters[8][i];
+       }
+
+       virtual void evaluate(const std::vector<const Scalar*>& _states_ptr, Eigen::VectorXs& residual_, std::vector<Eigen::MatrixXs>& jacobians_) const
+       {
+           assert(residual_.size() == RES);
+           jacobians_.clear();
+
+           assert(_states_ptr.size() == n_blocks);
+
+           // init jacobian
+           for(auto i = 0; i < n_blocks; ++i)
+           {
+              Eigen::MatrixXs Ji = Eigen::MatrixXs::Zero(RES, state_block_sizes_[i]);
+              jacobians_.push_back(Ji);
+           }
+
+           // update jets real part
+           updateJetsRealPart(_states_ptr);
+
+           // call functor
+           (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                             jets_1_->data(),
+                                             jets_2_->data(),
+                                             jets_3_->data(),
+                                             jets_4_->data(),
+                                             jets_5_->data(),
+                                             jets_6_->data(),
+                                             jets_7_->data(),
+                                             jets_8_->data(),
+                                             residuals_jets_->data());
+
+           // fill the residual vector
+           for (auto i = 0; i < RES; i++)
+               residual_(i) = (*residuals_jets_)[i].a;
+
+           // fill the jacobian matrices
+           for (auto i = 0; i<n_blocks; i++)
+               if (!state_ptrs_[i]->isFixed())
+                   for (unsigned int row = 0; row < RES; row++)
+                       std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                 (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                 jacobians_[i].data() + row * state_block_sizes_.at(i));
+
+          // print jacobian matrices
+//           for (auto i = 0; i < n_blocks; i++)
+//               std::cout << jacobians_[i] << std::endl << std::endl;
+       }
+
+       virtual std::vector<Scalar*> getStateScalarPtrVector() const
+       {
+           return std::vector<Scalar*>({state_ptrs_[0]->getPtr(),
+                                        state_ptrs_[1]->getPtr(),
+                                        state_ptrs_[2]->getPtr(),
+                                        state_ptrs_[3]->getPtr(),
+                                        state_ptrs_[4]->getPtr(),
+                                        state_ptrs_[5]->getPtr(),
+                                        state_ptrs_[6]->getPtr(),
+                                        state_ptrs_[7]->getPtr(),
+                                        state_ptrs_[8]->getPtr()
+                                        });
+       }
+
+       virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const
+       {
+           return state_ptrs_;
+       }
+
+       virtual std::vector<unsigned int> getStateSizes() const
+       {
+           return state_block_sizes_;
+       }
+
+       virtual unsigned int getSize() const
+       {
+           return RES;
+       }
+};
+
+////////////////// SPECIALIZATION 8 BLOCKS ////////////////////////////////////////////////////////////////////////
+
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7>
+class ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0> : public ConstraintBase
+{
+   public:
+
+       static const unsigned int residualSize = RES;
+       static const unsigned int block0Size = B0;
+       static const unsigned int block1Size = B1;
+       static const unsigned int block2Size = B2;
+       static const unsigned int block3Size = B3;
+       static const unsigned int block4Size = B4;
+       static const unsigned int block5Size = B5;
+       static const unsigned int block6Size = B6;
+       static const unsigned int block7Size = B7;
+       static const unsigned int block8Size = 0;
+       static const unsigned int block9Size = 0;
+       static const unsigned int n_blocks = 8;
+
+       static const std::vector<unsigned int> state_block_sizes_;
+
+       typedef ceres::Jet<Scalar, B0 + B1 + B2 + B3 + B4 +
+                                  B5 + B6 + B7> WolfJet;
+
+   protected:
+
+       std::vector<StateBlockPtr> state_ptrs_;
+
+       static const std::vector<unsigned int> jacobian_locations_;
+       std::array<WolfJet, RES>* residuals_jets_;
+
+       std::array<WolfJet, B0>* jets_0_;
+       std::array<WolfJet, B1>* jets_1_;
+       std::array<WolfJet, B2>* jets_2_;
+       std::array<WolfJet, B3>* jets_3_;
+       std::array<WolfJet, B4>* jets_4_;
+       std::array<WolfJet, B5>* jets_5_;
+       std::array<WolfJet, B6>* jets_6_;
+       std::array<WolfJet, B7>* jets_7_;
+
+   public:
+
+       ConstraintAutodiff(ConstraintType _tp,
+                          const FrameBasePtr& _frame_other_ptr,
+                          const FeatureBasePtr& _feature_other_ptr,
+                          const LandmarkBasePtr& _landmark_other_ptr,
+                          const ProcessorBasePtr& _processor_ptr,
+                          bool _apply_loss_function,
+                          ConstraintStatus _status,
+                          StateBlockPtr _state0Ptr,
+                          StateBlockPtr _state1Ptr,
+                          StateBlockPtr _state2Ptr,
+                          StateBlockPtr _state3Ptr,
+                          StateBlockPtr _state4Ptr,
+                          StateBlockPtr _state5Ptr,
+                          StateBlockPtr _state6Ptr,
+                          StateBlockPtr _state7Ptr) :
+           ConstraintBase(_tp, _frame_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status),
+           state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr}),
+           residuals_jets_(new std::array<WolfJet, RES>),
+           jets_0_(new std::array<WolfJet, B0>),
+           jets_1_(new std::array<WolfJet, B1>),
+           jets_2_(new std::array<WolfJet, B2>),
+           jets_3_(new std::array<WolfJet, B3>),
+           jets_4_(new std::array<WolfJet, B4>),
+           jets_5_(new std::array<WolfJet, B5>),
+           jets_6_(new std::array<WolfJet, B6>),
+           jets_7_(new std::array<WolfJet, B7>)
+       {
+           // initialize jets
+           unsigned int last_jet_idx = 0;
+           for (auto i = 0; i < B0; i++)
+              (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B1; i++)
+              (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B2; i++)
+              (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B3; i++)
+              (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B4; i++)
+              (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B5; i++)
+              (*jets_5_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B6; i++)
+              (*jets_6_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B7; i++)
+              (*jets_7_)[i] = WolfJet(0, last_jet_idx++);
+           state_ptrs_.resize(n_blocks);
+       }
+
+       virtual ~ConstraintAutodiff()
+       {
+           delete jets_0_;
+           delete jets_1_;
+           delete jets_2_;
+           delete jets_3_;
+           delete jets_4_;
+           delete jets_5_;
+           delete jets_6_;
+           delete jets_7_;
+           delete residuals_jets_;
+       }
+
+       virtual JacobianMethod getJacobianMethod() const
+       {
+           return JAC_AUTO;
+       }
+
+       virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const
+       {
+           // only residuals
+           if (jacobians == nullptr)
+           {
+               (*static_cast<CtrT const*>(this))(parameters[0],
+                                                        parameters[1],
+                                                        parameters[2],
+                                                        parameters[3],
+                                                        parameters[4],
+                                                        parameters[5],
+                                                        parameters[6],
+                                                        parameters[7],
+                                                        residuals);
+           }
+           // also compute jacobians
+           else
+           {
+               // update jets real part
+               std::vector<double const*> param_vec;
+               param_vec.assign(parameters,parameters+n_blocks);
+               updateJetsRealPart(param_vec);
+
+               // call functor
+               (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                                        jets_1_->data(),
+                                                        jets_2_->data(),
+                                                        jets_3_->data(),
+                                                        jets_4_->data(),
+                                                        jets_5_->data(),
+                                                        jets_6_->data(),
+                                                        jets_7_->data(),
+                                                        residuals_jets_->data());
+
+               // fill the residual array
+               for (auto i = 0; i < RES; i++)
+                   residuals[i] = (*residuals_jets_)[i].a;
+
+               // fill the jacobian matrices
+               for (auto i = 0; i<n_blocks; i++)
+                   if (jacobians[i] != nullptr)
+                       for (unsigned int row = 0; row < RES; row++)
+                           std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                     (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                     jacobians[i] + row * state_block_sizes_.at(i));
+           }
+           return true;
+       }
+
+       void updateJetsRealPart(const std::vector<double const*>& parameters) const
+       {
+           // update jets real part
+           for (auto i = 0; i < B0; i++)
+               (*jets_0_)[i].a = parameters[0][i];
+           for (auto i = 0; i < B1; i++)
+               (*jets_1_)[i].a = parameters[1][i];
+           for (auto i = 0; i < B2; i++)
+               (*jets_2_)[i].a = parameters[2][i];
+           for (auto i = 0; i < B3; i++)
+               (*jets_3_)[i].a = parameters[3][i];
+           for (auto i = 0; i < B4; i++)
+               (*jets_4_)[i].a = parameters[4][i];
+           for (auto i = 0; i < B5; i++)
+               (*jets_5_)[i].a = parameters[5][i];
+           for (auto i = 0; i < B6; i++)
+               (*jets_6_)[i].a = parameters[6][i];
+           for (auto i = 0; i < B7; i++)
+               (*jets_7_)[i].a = parameters[7][i];
+       }
+
+       virtual void evaluate(const std::vector<const Scalar*>& _states_ptr, Eigen::VectorXs& residual_, std::vector<Eigen::MatrixXs>& jacobians_) const
+       {
+           assert(residual_.size() == RES);
+           jacobians_.clear();
+
+           assert(_states_ptr.size() == n_blocks);
+
+           // init jacobian
+           for(auto i = 0; i < n_blocks; ++i)
+           {
+              Eigen::MatrixXs Ji = Eigen::MatrixXs::Zero(RES, state_block_sizes_[i]);
+              jacobians_.push_back(Ji);
+           }
+
+           // update jets real part
+           updateJetsRealPart(_states_ptr);
+
+           // call functor
+           (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                             jets_1_->data(),
+                                             jets_2_->data(),
+                                             jets_3_->data(),
+                                             jets_4_->data(),
+                                             jets_5_->data(),
+                                             jets_6_->data(),
+                                             jets_7_->data(),
+                                             residuals_jets_->data());
+
+           // fill the residual vector
+           for (auto i = 0; i < RES; i++)
+               residual_(i) = (*residuals_jets_)[i].a;
+
+           // fill the jacobian matrices
+           for (auto i = 0; i<n_blocks; i++)
+               if (!state_ptrs_[i]->isFixed())
+                   for (unsigned int row = 0; row < RES; row++)
+                       std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                 (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                 jacobians_[i].data() + row * state_block_sizes_.at(i));
+
+          // print jacobian matrices
+//           for (auto i = 0; i < n_blocks; i++)
+//               std::cout << jacobians_[i] << std::endl << std::endl;
+       }
+
+       virtual std::vector<Scalar*> getStateScalarPtrVector() const
+       {
+           return std::vector<Scalar*>({state_ptrs_[0]->getPtr(),
+                                        state_ptrs_[1]->getPtr(),
+                                        state_ptrs_[2]->getPtr(),
+                                        state_ptrs_[3]->getPtr(),
+                                        state_ptrs_[4]->getPtr(),
+                                        state_ptrs_[5]->getPtr(),
+                                        state_ptrs_[6]->getPtr(),
+                                        state_ptrs_[7]->getPtr()
+                                        });
+       }
+
+       virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const
+       {
+           return state_ptrs_;
+       }
+
+       virtual std::vector<unsigned int> getStateSizes() const
+       {
+           return state_block_sizes_;
+       }
+
+       virtual unsigned int getSize() const
+       {
+           return RES;
+       }
+};
+
+////////////////// SPECIALIZATION 7 BLOCKS ////////////////////////////////////////////////////////////////////////
+
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6>
+class ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0> : public ConstraintBase
+{
+   public:
+
+       static const unsigned int residualSize = RES;
+       static const unsigned int block0Size = B0;
+       static const unsigned int block1Size = B1;
+       static const unsigned int block2Size = B2;
+       static const unsigned int block3Size = B3;
+       static const unsigned int block4Size = B4;
+       static const unsigned int block5Size = B5;
+       static const unsigned int block6Size = B6;
+       static const unsigned int block7Size = 0;
+       static const unsigned int block8Size = 0;
+       static const unsigned int block9Size = 0;
+       static const unsigned int n_blocks = 7;
+
+       static const std::vector<unsigned int> state_block_sizes_;
+
+       typedef ceres::Jet<Scalar, B0 + B1 + B2 + B3 + B4 +
+                                  B5 + B6> WolfJet;
+
+   protected:
+
+       std::vector<StateBlockPtr> state_ptrs_;
+
+       static const std::vector<unsigned int> jacobian_locations_;
+       std::array<WolfJet, RES>* residuals_jets_;
+
+       std::array<WolfJet, B0>* jets_0_;
+       std::array<WolfJet, B1>* jets_1_;
+       std::array<WolfJet, B2>* jets_2_;
+       std::array<WolfJet, B3>* jets_3_;
+       std::array<WolfJet, B4>* jets_4_;
+       std::array<WolfJet, B5>* jets_5_;
+       std::array<WolfJet, B6>* jets_6_;
+
+   public:
+
+       ConstraintAutodiff(ConstraintType _tp,
+                          const FrameBasePtr& _frame_other_ptr,
+                          const FeatureBasePtr& _feature_other_ptr,
+                          const LandmarkBasePtr& _landmark_other_ptr,
+                          const ProcessorBasePtr& _processor_ptr,
+                          bool _apply_loss_function,
+                          ConstraintStatus _status,
+                          StateBlockPtr _state0Ptr,
+                          StateBlockPtr _state1Ptr,
+                          StateBlockPtr _state2Ptr,
+                          StateBlockPtr _state3Ptr,
+                          StateBlockPtr _state4Ptr,
+                          StateBlockPtr _state5Ptr,
+                          StateBlockPtr _state6Ptr) :
+           ConstraintBase(_tp, _frame_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status),
+           state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr}),
+           residuals_jets_(new std::array<WolfJet, RES>),
+           jets_0_(new std::array<WolfJet, B0>),
+           jets_1_(new std::array<WolfJet, B1>),
+           jets_2_(new std::array<WolfJet, B2>),
+           jets_3_(new std::array<WolfJet, B3>),
+           jets_4_(new std::array<WolfJet, B4>),
+           jets_5_(new std::array<WolfJet, B5>),
+           jets_6_(new std::array<WolfJet, B6>)
+       {
+           // initialize jets
+           unsigned int last_jet_idx = 0;
+           for (auto i = 0; i < B0; i++)
+              (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B1; i++)
+              (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B2; i++)
+              (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B3; i++)
+              (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B4; i++)
+              (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B5; i++)
+              (*jets_5_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B6; i++)
+              (*jets_6_)[i] = WolfJet(0, last_jet_idx++);
+           state_ptrs_.resize(n_blocks);
+       }
+
+       virtual ~ConstraintAutodiff()
+       {
+           delete jets_0_;
+           delete jets_1_;
+           delete jets_2_;
+           delete jets_3_;
+           delete jets_4_;
+           delete jets_5_;
+           delete jets_6_;
+           delete residuals_jets_;
+       }
+
+       virtual JacobianMethod getJacobianMethod() const
+       {
+           return JAC_AUTO;
+       }
+
+       virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const
+       {
+           // only residuals
+           if (jacobians == nullptr)
+           {
+               (*static_cast<CtrT const*>(this))(parameters[0],
+                                                        parameters[1],
+                                                        parameters[2],
+                                                        parameters[3],
+                                                        parameters[4],
+                                                        parameters[5],
+                                                        parameters[6],
+                                                        residuals);
+           }
+           // also compute jacobians
+           else
+           {
+               // update jets real part
+               std::vector<double const*> param_vec;
+               param_vec.assign(parameters,parameters+n_blocks);
+               updateJetsRealPart(param_vec);
+
+               // call functor
+               (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                                        jets_1_->data(),
+                                                        jets_2_->data(),
+                                                        jets_3_->data(),
+                                                        jets_4_->data(),
+                                                        jets_5_->data(),
+                                                        jets_6_->data(),
+                                                        residuals_jets_->data());
+
+               // fill the residual array
+               for (auto i = 0; i < RES; i++)
+                   residuals[i] = (*residuals_jets_)[i].a;
+
+               // fill the jacobian matrices
+               for (auto i = 0; i<n_blocks; i++)
+                   if (jacobians[i] != nullptr)
+                       for (unsigned int row = 0; row < RES; row++)
+                           std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                     (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                     jacobians[i] + row * state_block_sizes_.at(i));
+           }
+           return true;
+       }
+
+       void updateJetsRealPart(const std::vector<double const*>& parameters) const
+       {
+           // update jets real part
+           for (auto i = 0; i < B0; i++)
+               (*jets_0_)[i].a = parameters[0][i];
+           for (auto i = 0; i < B1; i++)
+               (*jets_1_)[i].a = parameters[1][i];
+           for (auto i = 0; i < B2; i++)
+               (*jets_2_)[i].a = parameters[2][i];
+           for (auto i = 0; i < B3; i++)
+               (*jets_3_)[i].a = parameters[3][i];
+           for (auto i = 0; i < B4; i++)
+               (*jets_4_)[i].a = parameters[4][i];
+           for (auto i = 0; i < B5; i++)
+               (*jets_5_)[i].a = parameters[5][i];
+           for (auto i = 0; i < B6; i++)
+               (*jets_6_)[i].a = parameters[6][i];
+       }
+
+       virtual void evaluate(const std::vector<const Scalar*>& _states_ptr, Eigen::VectorXs& residual_, std::vector<Eigen::MatrixXs>& jacobians_) const
+       {
+           assert(residual_.size() == RES);
+           jacobians_.clear();
+
+           assert(_states_ptr.size() == n_blocks);
+
+           // init jacobian
+           for(auto i = 0; i < n_blocks; ++i)
+           {
+              Eigen::MatrixXs Ji = Eigen::MatrixXs::Zero(RES, state_block_sizes_[i]);
+              jacobians_.push_back(Ji);
+           }
+
+           // update jets real part
+           updateJetsRealPart(_states_ptr);
+
+           // call functor
+           (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                             jets_1_->data(),
+                                             jets_2_->data(),
+                                             jets_3_->data(),
+                                             jets_4_->data(),
+                                             jets_5_->data(),
+                                             jets_6_->data(),
+                                             residuals_jets_->data());
+
+           // fill the residual vector
+           for (auto i = 0; i < RES; i++)
+               residual_(i) = (*residuals_jets_)[i].a;
+
+           // fill the jacobian matrices
+           for (auto i = 0; i<n_blocks; i++)
+               if (!state_ptrs_[i]->isFixed())
+                   for (unsigned int row = 0; row < RES; row++)
+                       std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                 (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                 jacobians_[i].data() + row * state_block_sizes_.at(i));
+
+          // print jacobian matrices
+//           for (auto i = 0; i < n_blocks; i++)
+//               std::cout << jacobians_[i] << std::endl << std::endl;
+       }
+
+       virtual std::vector<Scalar*> getStateScalarPtrVector() const
+       {
+           return std::vector<Scalar*>({state_ptrs_[0]->getPtr(),
+                                        state_ptrs_[1]->getPtr(),
+                                        state_ptrs_[2]->getPtr(),
+                                        state_ptrs_[3]->getPtr(),
+                                        state_ptrs_[4]->getPtr(),
+                                        state_ptrs_[5]->getPtr(),
+                                        state_ptrs_[6]->getPtr()
+                                        });
+       }
+
+       virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const
+       {
+           return state_ptrs_;
+       }
+
+       virtual std::vector<unsigned int> getStateSizes() const
+       {
+           return state_block_sizes_;
+       }
+
+       virtual unsigned int getSize() const
+       {
+           return RES;
+       }
+};
+
+////////////////// SPECIALIZATION 6 BLOCKS ////////////////////////////////////////////////////////////////////////
+
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5>
+class ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0> : public ConstraintBase
+{
+   public:
+
+       static const unsigned int residualSize = RES;
+       static const unsigned int block0Size = B0;
+       static const unsigned int block1Size = B1;
+       static const unsigned int block2Size = B2;
+       static const unsigned int block3Size = B3;
+       static const unsigned int block4Size = B4;
+       static const unsigned int block5Size = B5;
+       static const unsigned int block6Size = 0;
+       static const unsigned int block7Size = 0;
+       static const unsigned int block8Size = 0;
+       static const unsigned int block9Size = 0;
+       static const unsigned int n_blocks = 6;
+
+       static const std::vector<unsigned int> state_block_sizes_;
+
+       typedef ceres::Jet<Scalar, B0 + B1 + B2 + B3 + B4 +
+                                  B5> WolfJet;
+
+   protected:
+
+       std::vector<StateBlockPtr> state_ptrs_;
+
+       static const std::vector<unsigned int> jacobian_locations_;
+       std::array<WolfJet, RES>* residuals_jets_;
+
+       std::array<WolfJet, B0>* jets_0_;
+       std::array<WolfJet, B1>* jets_1_;
+       std::array<WolfJet, B2>* jets_2_;
+       std::array<WolfJet, B3>* jets_3_;
+       std::array<WolfJet, B4>* jets_4_;
+       std::array<WolfJet, B5>* jets_5_;
+
+   public:
+
+       ConstraintAutodiff(ConstraintType _tp,
+                          const FrameBasePtr& _frame_other_ptr,
+                          const FeatureBasePtr& _feature_other_ptr,
+                          const LandmarkBasePtr& _landmark_other_ptr,
+                          const ProcessorBasePtr& _processor_ptr,
+                          bool _apply_loss_function,
+                          ConstraintStatus _status,
+                          StateBlockPtr _state0Ptr,
+                          StateBlockPtr _state1Ptr,
+                          StateBlockPtr _state2Ptr,
+                          StateBlockPtr _state3Ptr,
+                          StateBlockPtr _state4Ptr,
+                          StateBlockPtr _state5Ptr) :
+           ConstraintBase(_tp, _frame_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status),
+           state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr}),
+           residuals_jets_(new std::array<WolfJet, RES>),
+           jets_0_(new std::array<WolfJet, B0>),
+           jets_1_(new std::array<WolfJet, B1>),
+           jets_2_(new std::array<WolfJet, B2>),
+           jets_3_(new std::array<WolfJet, B3>),
+           jets_4_(new std::array<WolfJet, B4>),
+           jets_5_(new std::array<WolfJet, B5>)
+       {
+           // initialize jets
+           unsigned int last_jet_idx = 0;
+           for (auto i = 0; i < B0; i++)
+              (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B1; i++)
+              (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B2; i++)
+              (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B3; i++)
+              (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B4; i++)
+              (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B5; i++)
+              (*jets_5_)[i] = WolfJet(0, last_jet_idx++);
+           state_ptrs_.resize(n_blocks);
+       }
+
+       virtual ~ConstraintAutodiff()
+       {
+           delete jets_0_;
+           delete jets_1_;
+           delete jets_2_;
+           delete jets_3_;
+           delete jets_4_;
+           delete jets_5_;
+           delete residuals_jets_;
+       }
+
+       virtual JacobianMethod getJacobianMethod() const
+       {
+           return JAC_AUTO;
+       }
+
+       virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const
+       {
+           // only residuals
+           if (jacobians == nullptr)
+           {
+               (*static_cast<CtrT const*>(this))(parameters[0],
+                                                        parameters[1],
+                                                        parameters[2],
+                                                        parameters[3],
+                                                        parameters[4],
+                                                        parameters[5],
+                                                        residuals);
+           }
+           // also compute jacobians
+           else
+           {
+               // update jets real part
+               std::vector<double const*> param_vec;
+               param_vec.assign(parameters,parameters+n_blocks);
+               updateJetsRealPart(param_vec);
+
+               // call functor
+               (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                                        jets_1_->data(),
+                                                        jets_2_->data(),
+                                                        jets_3_->data(),
+                                                        jets_4_->data(),
+                                                        jets_5_->data(),
+                                                        residuals_jets_->data());
+
+               // fill the residual array
+               for (auto i = 0; i < RES; i++)
+                   residuals[i] = (*residuals_jets_)[i].a;
+
+               // fill the jacobian matrices
+               for (auto i = 0; i<n_blocks; i++)
+                   if (jacobians[i] != nullptr)
+                       for (unsigned int row = 0; row < RES; row++)
+                           std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                     (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                     jacobians[i] + row * state_block_sizes_.at(i));
+           }
+           return true;
+       }
+
+       void updateJetsRealPart(const std::vector<double const*>& parameters) const
+       {
+           // update jets real part
+           for (auto i = 0; i < B0; i++)
+               (*jets_0_)[i].a = parameters[0][i];
+           for (auto i = 0; i < B1; i++)
+               (*jets_1_)[i].a = parameters[1][i];
+           for (auto i = 0; i < B2; i++)
+               (*jets_2_)[i].a = parameters[2][i];
+           for (auto i = 0; i < B3; i++)
+               (*jets_3_)[i].a = parameters[3][i];
+           for (auto i = 0; i < B4; i++)
+               (*jets_4_)[i].a = parameters[4][i];
+           for (auto i = 0; i < B5; i++)
+               (*jets_5_)[i].a = parameters[5][i];
+       }
+
+       virtual void evaluate(const std::vector<const Scalar*>& _states_ptr, Eigen::VectorXs& residual_, std::vector<Eigen::MatrixXs>& jacobians_) const
+       {
+           assert(residual_.size() == RES);
+           jacobians_.clear();
+
+           assert(_states_ptr.size() == n_blocks);
+
+           // init jacobian
+           for(auto i = 0; i < n_blocks; ++i)
+           {
+              Eigen::MatrixXs Ji = Eigen::MatrixXs::Zero(RES, state_block_sizes_[i]);
+              jacobians_.push_back(Ji);
+           }
+
+           // update jets real part
+           updateJetsRealPart(_states_ptr);
+
+           // call functor
+           (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                             jets_1_->data(),
+                                             jets_2_->data(),
+                                             jets_3_->data(),
+                                             jets_4_->data(),
+                                             jets_5_->data(),
+                                             residuals_jets_->data());
+
+           // fill the residual vector
+           for (auto i = 0; i < RES; i++)
+               residual_(i) = (*residuals_jets_)[i].a;
+
+           // fill the jacobian matrices
+           for (auto i = 0; i<n_blocks; i++)
+               if (!state_ptrs_[i]->isFixed())
+                   for (unsigned int row = 0; row < RES; row++)
+                       std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                 (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                 jacobians_[i].data() + row * state_block_sizes_.at(i));
+
+          // print jacobian matrices
+//           for (auto i = 0; i < n_blocks; i++)
+//               std::cout << jacobians_[i] << std::endl << std::endl;
+       }
+
+       virtual std::vector<Scalar*> getStateScalarPtrVector() const
+       {
+           return std::vector<Scalar*>({state_ptrs_[0]->getPtr(),
+                                        state_ptrs_[1]->getPtr(),
+                                        state_ptrs_[2]->getPtr(),
+                                        state_ptrs_[3]->getPtr(),
+                                        state_ptrs_[4]->getPtr(),
+                                        state_ptrs_[5]->getPtr()
+                                        });
+       }
+
+       virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const
+       {
+           return state_ptrs_;
+       }
+
+       virtual std::vector<unsigned int> getStateSizes() const
+       {
+           return state_block_sizes_;
+       }
+
+       virtual unsigned int getSize() const
+       {
+           return RES;
+       }
+};
+
+////////////////// SPECIALIZATION 5 BLOCKS ////////////////////////////////////////////////////////////////////////
+
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4>
+class ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,0,0,0,0,0> : public ConstraintBase
+{
+   public:
+
+       static const unsigned int residualSize = RES;
+       static const unsigned int block0Size = B0;
+       static const unsigned int block1Size = B1;
+       static const unsigned int block2Size = B2;
+       static const unsigned int block3Size = B3;
+       static const unsigned int block4Size = B4;
+       static const unsigned int block5Size = 0;
+       static const unsigned int block6Size = 0;
+       static const unsigned int block7Size = 0;
+       static const unsigned int block8Size = 0;
+       static const unsigned int block9Size = 0;
+       static const unsigned int n_blocks = 5;
+
+       static const std::vector<unsigned int> state_block_sizes_;
+
+       typedef ceres::Jet<Scalar, B0 + B1 + B2 + B3 + B4> WolfJet;
+
+   protected:
+
+       std::vector<StateBlockPtr> state_ptrs_;
+
+       static const std::vector<unsigned int> jacobian_locations_;
+       std::array<WolfJet, RES>* residuals_jets_;
+
+       std::array<WolfJet, B0>* jets_0_;
+       std::array<WolfJet, B1>* jets_1_;
+       std::array<WolfJet, B2>* jets_2_;
+       std::array<WolfJet, B3>* jets_3_;
+       std::array<WolfJet, B4>* jets_4_;
+
+   public:
+
+       ConstraintAutodiff(ConstraintType _tp,
+                          const FrameBasePtr& _frame_other_ptr,
+                          const FeatureBasePtr& _feature_other_ptr,
+                          const LandmarkBasePtr& _landmark_other_ptr,
+                          const ProcessorBasePtr& _processor_ptr,
+                          bool _apply_loss_function,
+                          ConstraintStatus _status,
+                          StateBlockPtr _state0Ptr,
+                          StateBlockPtr _state1Ptr,
+                          StateBlockPtr _state2Ptr,
+                          StateBlockPtr _state3Ptr,
+                          StateBlockPtr _state4Ptr) :
+           ConstraintBase(_tp, _frame_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status),
+           state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr}),
+           residuals_jets_(new std::array<WolfJet, RES>),
+           jets_0_(new std::array<WolfJet, B0>),
+           jets_1_(new std::array<WolfJet, B1>),
+           jets_2_(new std::array<WolfJet, B2>),
+           jets_3_(new std::array<WolfJet, B3>),
+           jets_4_(new std::array<WolfJet, B4>)
+       {
+           // initialize jets
+           unsigned int last_jet_idx = 0;
+           for (auto i = 0; i < B0; i++)
+              (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B1; i++)
+              (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B2; i++)
+              (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B3; i++)
+              (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B4; i++)
+              (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
+           state_ptrs_.resize(n_blocks);
+       }
+
+       virtual ~ConstraintAutodiff()
+       {
+           delete jets_0_;
+           delete jets_1_;
+           delete jets_2_;
+           delete jets_3_;
+           delete jets_4_;
+           delete residuals_jets_;
+       }
+
+       virtual JacobianMethod getJacobianMethod() const
+       {
+           return JAC_AUTO;
+       }
+
+       virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const
+       {
+           // only residuals
+           if (jacobians == nullptr)
+           {
+               (*static_cast<CtrT const*>(this))(parameters[0],
+                                                        parameters[1],
+                                                        parameters[2],
+                                                        parameters[3],
+                                                        parameters[4],
+                                                        residuals);
+           }
+           // also compute jacobians
+           else
+           {
+               // update jets real part
+               std::vector<double const*> param_vec;
+               param_vec.assign(parameters,parameters+n_blocks);
+               updateJetsRealPart(param_vec);
+
+               // call functor
+               (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                                        jets_1_->data(),
+                                                        jets_2_->data(),
+                                                        jets_3_->data(),
+                                                        jets_4_->data(),
+                                                        residuals_jets_->data());
+
+               // fill the residual array
+               for (auto i = 0; i < RES; i++)
+                   residuals[i] = (*residuals_jets_)[i].a;
+
+               // fill the jacobian matrices
+               for (auto i = 0; i<n_blocks; i++)
+                   if (jacobians[i] != nullptr)
+                       for (unsigned int row = 0; row < RES; row++)
+                           std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                     (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                     jacobians[i] + row * state_block_sizes_.at(i));
+           }
+           return true;
+       }
+
+       void updateJetsRealPart(const std::vector<double const*>& parameters) const
+       {
+           // update jets real part
+           for (auto i = 0; i < B0; i++)
+               (*jets_0_)[i].a = parameters[0][i];
+           for (auto i = 0; i < B1; i++)
+               (*jets_1_)[i].a = parameters[1][i];
+           for (auto i = 0; i < B2; i++)
+               (*jets_2_)[i].a = parameters[2][i];
+           for (auto i = 0; i < B3; i++)
+               (*jets_3_)[i].a = parameters[3][i];
+           for (auto i = 0; i < B4; i++)
+               (*jets_4_)[i].a = parameters[4][i];
+       }
+
+       virtual void evaluate(const std::vector<const Scalar*>& _states_ptr, Eigen::VectorXs& residual_, std::vector<Eigen::MatrixXs>& jacobians_) const
+       {
+           assert(residual_.size() == RES);
+           jacobians_.clear();
+
+           assert(_states_ptr.size() == n_blocks);
+
+           // init jacobian
+           for(auto i = 0; i < n_blocks; ++i)
+           {
+              Eigen::MatrixXs Ji = Eigen::MatrixXs::Zero(RES, state_block_sizes_[i]);
+              jacobians_.push_back(Ji);
+           }
+
+           // update jets real part
+           updateJetsRealPart(_states_ptr);
+
+           // call functor
+           (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                             jets_1_->data(),
+                                             jets_2_->data(),
+                                             jets_3_->data(),
+                                             jets_4_->data(),
+                                             residuals_jets_->data());
+
+           // fill the residual vector
+           for (auto i = 0; i < RES; i++)
+               residual_(i) = (*residuals_jets_)[i].a;
+
+           // fill the jacobian matrices
+           for (auto i = 0; i<n_blocks; i++)
+               if (!state_ptrs_[i]->isFixed())
+                   for (unsigned int row = 0; row < RES; row++)
+                       std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                 (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                 jacobians_[i].data() + row * state_block_sizes_.at(i));
+
+          // print jacobian matrices
+//           for (auto i = 0; i < n_blocks; i++)
+//               std::cout << jacobians_[i] << std::endl << std::endl;
+       }
+
+       virtual std::vector<Scalar*> getStateScalarPtrVector() const
+       {
+           return std::vector<Scalar*>({state_ptrs_[0]->getPtr(),
+                                        state_ptrs_[1]->getPtr(),
+                                        state_ptrs_[2]->getPtr(),
+                                        state_ptrs_[3]->getPtr(),
+                                        state_ptrs_[4]->getPtr(),
+                                        });
+       }
+
+       virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const
+       {
+           return state_ptrs_;
+       }
+
+       virtual std::vector<unsigned int> getStateSizes() const
+       {
+           return state_block_sizes_;
+       }
+
+       virtual unsigned int getSize() const
+       {
+           return RES;
+       }
+};
+
+////////////////// SPECIALIZATION 4 BLOCKS ////////////////////////////////////////////////////////////////////////
+
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3>
+class ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,0,0,0,0,0,0> : public ConstraintBase
+{
+   public:
+
+       static const unsigned int residualSize = RES;
+       static const unsigned int block0Size = B0;
+       static const unsigned int block1Size = B1;
+       static const unsigned int block2Size = B2;
+       static const unsigned int block3Size = B3;
+       static const unsigned int block4Size = 0;
+       static const unsigned int block5Size = 0;
+       static const unsigned int block6Size = 0;
+       static const unsigned int block7Size = 0;
+       static const unsigned int block8Size = 0;
+       static const unsigned int block9Size = 0;
+       static const unsigned int n_blocks = 4;
+
+       static const std::vector<unsigned int> state_block_sizes_;
+
+       typedef ceres::Jet<Scalar, B0 + B1 + B2 + B3> WolfJet;
+
+   protected:
+
+       std::vector<StateBlockPtr> state_ptrs_;
+
+       static const std::vector<unsigned int> jacobian_locations_;
+       std::array<WolfJet, RES>* residuals_jets_;
+
+       std::array<WolfJet, B0>* jets_0_;
+       std::array<WolfJet, B1>* jets_1_;
+       std::array<WolfJet, B2>* jets_2_;
+       std::array<WolfJet, B3>* jets_3_;
+
+   public:
+
+       ConstraintAutodiff(ConstraintType _tp,
+                          const FrameBasePtr& _frame_other_ptr,
+                          const FeatureBasePtr& _feature_other_ptr,
+                          const LandmarkBasePtr& _landmark_other_ptr,
+                          const ProcessorBasePtr& _processor_ptr,
+                          bool _apply_loss_function,
+                          ConstraintStatus _status,
+                          StateBlockPtr _state0Ptr,
+                          StateBlockPtr _state1Ptr,
+                          StateBlockPtr _state2Ptr,
+                          StateBlockPtr _state3Ptr) :
+           ConstraintBase(_tp, _frame_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status),
+           state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr}),
+           residuals_jets_(new std::array<WolfJet, RES>),
+           jets_0_(new std::array<WolfJet, B0>),
+           jets_1_(new std::array<WolfJet, B1>),
+           jets_2_(new std::array<WolfJet, B2>),
+           jets_3_(new std::array<WolfJet, B3>)
+       {
+           // initialize jets
+           unsigned int last_jet_idx = 0;
+           for (auto i = 0; i < B0; i++)
+              (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B1; i++)
+              (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B2; i++)
+              (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B3; i++)
+              (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
+           state_ptrs_.resize(n_blocks);
+       }
+
+       virtual ~ConstraintAutodiff()
+       {
+           delete jets_0_;
+           delete jets_1_;
+           delete jets_2_;
+           delete jets_3_;
+           delete residuals_jets_;
+       }
+
+       virtual JacobianMethod getJacobianMethod() const
+       {
+           return JAC_AUTO;
+       }
+
+       virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const
+       {
+           // only residuals
+           if (jacobians == nullptr)
+           {
+               (*static_cast<CtrT const*>(this))(parameters[0],
+                                                 parameters[1],
+                                                 parameters[2],
+                                                 parameters[3],
+                                                 residuals);
+           }
+           // also compute jacobians
+           else
+           {
+               // update jets real part
+               std::vector<double const*> param_vec;
+               param_vec.assign(parameters,parameters+n_blocks);
+               updateJetsRealPart(param_vec);
+
+               // call functor
+               (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                                 jets_1_->data(),
+                                                 jets_2_->data(),
+                                                 jets_3_->data(),
+                                                 residuals_jets_->data());
+
+               // fill the residual array
+               for (auto i = 0; i < RES; i++)
+                   residuals[i] = (*residuals_jets_)[i].a;
+
+               // fill the jacobian matrices
+               for (auto i = 0; i<n_blocks; i++)
+                   if (jacobians[i] != nullptr)
+                       for (unsigned int row = 0; row < RES; row++)
+                           std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                     (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                     jacobians[i] + row * state_block_sizes_.at(i));
+           }
+           return true;
+       }
+
+       void updateJetsRealPart(const std::vector<double const*>& parameters) const
+       {
+           // update jets real part
+           for (auto i = 0; i < B0; i++)
+               (*jets_0_)[i].a = parameters[0][i];
+           for (auto i = 0; i < B1; i++)
+               (*jets_1_)[i].a = parameters[1][i];
+           for (auto i = 0; i < B2; i++)
+               (*jets_2_)[i].a = parameters[2][i];
+           for (auto i = 0; i < B3; i++)
+               (*jets_3_)[i].a = parameters[3][i];
+       }
+
+       virtual void evaluate(const std::vector<const Scalar*>& _states_ptr, Eigen::VectorXs& residual_, std::vector<Eigen::MatrixXs>& jacobians_) const
+       {
+           assert(residual_.size() == RES);
+           jacobians_.clear();
+
+           assert(_states_ptr.size() == n_blocks);
+
+           // init jacobian
+           for(auto i = 0; i < n_blocks; ++i)
+           {
+              Eigen::MatrixXs Ji = Eigen::MatrixXs::Zero(RES, state_block_sizes_[i]);
+              jacobians_.push_back(Ji);
+           }
+
+           // update jets real part
+           updateJetsRealPart(_states_ptr);
+
+           // call functor
+           (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                             jets_1_->data(),
+                                             jets_2_->data(),
+                                             jets_3_->data(),
+                                             residuals_jets_->data());
+
+           // fill the residual vector
+           for (auto i = 0; i < RES; i++)
+               residual_(i) = (*residuals_jets_)[i].a;
+
+           // fill the jacobian matrices
+           for (auto i = 0; i<n_blocks; i++)
+               if (!state_ptrs_[i]->isFixed())
+                   for (unsigned int row = 0; row < RES; row++)
+                       std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                 (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                 jacobians_[i].data() + row * state_block_sizes_.at(i));
+
+          // print jacobian matrices
+//           for (auto i = 0; i < n_blocks; i++)
+//               std::cout << jacobians_[i] << std::endl << std::endl;
+       }
+
+       virtual std::vector<Scalar*> getStateScalarPtrVector() const
+       {
+           return std::vector<Scalar*>({state_ptrs_[0]->getPtr(),
+                                        state_ptrs_[1]->getPtr(),
+                                        state_ptrs_[2]->getPtr(),
+                                        state_ptrs_[3]->getPtr()
+                                        });
+       }
+
+       virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const
+       {
+           return state_ptrs_;
+       }
+
+       virtual std::vector<unsigned int> getStateSizes() const
+       {
+           return state_block_sizes_;
+       }
+
+       virtual unsigned int getSize() const
+       {
+           return RES;
+       }
+};
+
+////////////////// SPECIALIZATION 3 BLOCKS ////////////////////////////////////////////////////////////////////////
+
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2>
+class ConstraintAutodiff<CtrT,RES,B0,B1,B2,0,0,0,0,0,0,0> : public ConstraintBase
+{
+   public:
+
+       static const unsigned int residualSize = RES;
+       static const unsigned int block0Size = B0;
+       static const unsigned int block1Size = B1;
+       static const unsigned int block2Size = B2;
+       static const unsigned int block3Size = 0;
+       static const unsigned int block4Size = 0;
+       static const unsigned int block5Size = 0;
+       static const unsigned int block6Size = 0;
+       static const unsigned int block7Size = 0;
+       static const unsigned int block8Size = 0;
+       static const unsigned int block9Size = 0;
+       static const unsigned int n_blocks = 3;
+
+       static const std::vector<unsigned int> state_block_sizes_;
+
+       typedef ceres::Jet<Scalar, B0 + B1 + B2> WolfJet;
+
+   protected:
+
+       std::vector<StateBlockPtr> state_ptrs_;
+
+       static const std::vector<unsigned int> jacobian_locations_;
+       std::array<WolfJet, RES>* residuals_jets_;
+
+       std::array<WolfJet, B0>* jets_0_;
+       std::array<WolfJet, B1>* jets_1_;
+       std::array<WolfJet, B2>* jets_2_;
+
+   public:
+
+       ConstraintAutodiff(ConstraintType _tp,
+                          const FrameBasePtr& _frame_other_ptr,
+                          const FeatureBasePtr& _feature_other_ptr,
+                          const LandmarkBasePtr& _landmark_other_ptr,
+                          const ProcessorBasePtr& _processor_ptr,
+                          bool _apply_loss_function,
+                          ConstraintStatus _status,
+                          StateBlockPtr _state0Ptr,
+                          StateBlockPtr _state1Ptr,
+                          StateBlockPtr _state2Ptr) :
+           ConstraintBase(_tp, _frame_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status),
+           state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr}),
+           residuals_jets_(new std::array<WolfJet, RES>),
+           jets_0_(new std::array<WolfJet, B0>),
+           jets_1_(new std::array<WolfJet, B1>),
+           jets_2_(new std::array<WolfJet, B2>)
+       {
+           // initialize jets
+           unsigned int last_jet_idx = 0;
+           for (auto i = 0; i < B0; i++)
+              (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B1; i++)
+              (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B2; i++)
+              (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
+           state_ptrs_.resize(n_blocks);
+       }
+
+       virtual ~ConstraintAutodiff()
+       {
+           delete jets_0_;
+           delete jets_1_;
+           delete jets_2_;
+           delete residuals_jets_;
+       }
+
+       virtual JacobianMethod getJacobianMethod() const
+       {
+           return JAC_AUTO;
+       }
+
+       virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const
+       {
+           // only residuals
+           if (jacobians == nullptr)
+           {
+               (*static_cast<CtrT const*>(this))(parameters[0],
+                                                        parameters[1],
+                                                        parameters[2],
+                                                        residuals);
+           }
+           // also compute jacobians
+           else
+           {
+               // update jets real part
+               std::vector<double const*> param_vec;
+               param_vec.assign(parameters,parameters+n_blocks);
+               updateJetsRealPart(param_vec);
+
+               // call functor
+               (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                                        jets_1_->data(),
+                                                        jets_2_->data(),
+                                                        residuals_jets_->data());
+
+               // fill the residual array
+               for (auto i = 0; i < RES; i++)
+                   residuals[i] = (*residuals_jets_)[i].a;
+
+               // fill the jacobian matrices
+               for (auto i = 0; i<n_blocks; i++)
+                   if (jacobians[i] != nullptr)
+                       for (unsigned int row = 0; row < RES; row++)
+                           std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                     (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                     jacobians[i] + row * state_block_sizes_.at(i));
+           }
+           return true;
+       }
+
+       void updateJetsRealPart(const std::vector<double const*>& parameters) const
+       {
+           // update jets real part
+           for (auto i = 0; i < B0; i++)
+               (*jets_0_)[i].a = parameters[0][i];
+           for (auto i = 0; i < B1; i++)
+               (*jets_1_)[i].a = parameters[1][i];
+           for (auto i = 0; i < B2; i++)
+               (*jets_2_)[i].a = parameters[2][i];
+       }
+
+       virtual void evaluate(const std::vector<const Scalar*>& _states_ptr, Eigen::VectorXs& residual_, std::vector<Eigen::MatrixXs>& jacobians_) const
+       {
+           assert(residual_.size() == RES);
+           jacobians_.clear();
+
+           assert(_states_ptr.size() == n_blocks);
+
+           // init jacobian
+           for(auto i = 0; i < n_blocks; ++i)
+           {
+              Eigen::MatrixXs Ji = Eigen::MatrixXs::Zero(RES, state_block_sizes_[i]);
+              jacobians_.push_back(Ji);
+           }
+
+           // update jets real part
+           updateJetsRealPart(_states_ptr);
+
+           // call functor
+           (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                             jets_1_->data(),
+                                             jets_2_->data(),
+                                             residuals_jets_->data());
+
+           // fill the residual vector
+           for (auto i = 0; i < RES; i++)
+               residual_(i) = (*residuals_jets_)[i].a;
+
+           // fill the jacobian matrices
+           for (auto i = 0; i<n_blocks; i++)
+               if (!state_ptrs_[i]->isFixed())
+                   for (unsigned int row = 0; row < RES; row++)
+                       std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                 (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                 jacobians_[i].data() + row * state_block_sizes_.at(i));
+
+          // print jacobian matrices
+//           for (auto i = 0; i < n_blocks; i++)
+//               std::cout << jacobians_[i] << std::endl << std::endl;
+       }
+
+       virtual std::vector<Scalar*> getStateScalarPtrVector() const
+       {
+           return std::vector<Scalar*>({state_ptrs_[0]->getPtr(),
+                                        state_ptrs_[1]->getPtr(),
+                                        state_ptrs_[2]->getPtr()
+                                        });
+       }
+
+       virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const
+       {
+           return state_ptrs_;
+       }
+
+       virtual std::vector<unsigned int> getStateSizes() const
+       {
+           return state_block_sizes_;
+       }
+
+       virtual unsigned int getSize() const
+       {
+           return RES;
+       }
+};
+
+////////////////// SPECIALIZATION 2 BLOCKS ////////////////////////////////////////////////////////////////////////
+
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1>
+class ConstraintAutodiff<CtrT,RES,B0,B1,0,0,0,0,0,0,0,0> : public ConstraintBase
+{
+   public:
+
+       static const unsigned int residualSize = RES;
+       static const unsigned int block0Size = B0;
+       static const unsigned int block1Size = B1;
+       static const unsigned int block2Size = 0;
+       static const unsigned int block3Size = 0;
+       static const unsigned int block4Size = 0;
+       static const unsigned int block5Size = 0;
+       static const unsigned int block6Size = 0;
+       static const unsigned int block7Size = 0;
+       static const unsigned int block8Size = 0;
+       static const unsigned int block9Size = 0;
+       static const unsigned int n_blocks = 2;
+
+       static const std::vector<unsigned int> state_block_sizes_;
+
+       typedef ceres::Jet<Scalar, B0 + B1> WolfJet;
+
+   protected:
+
+       std::vector<StateBlockPtr> state_ptrs_;
+
+       static const std::vector<unsigned int> jacobian_locations_;
+       std::array<WolfJet, RES>* residuals_jets_;
+
+       std::array<WolfJet, B0>* jets_0_;
+       std::array<WolfJet, B1>* jets_1_;
+
+   public:
+
+       ConstraintAutodiff(ConstraintType _tp,
+                          const FrameBasePtr& _frame_other_ptr,
+                          const FeatureBasePtr& _feature_other_ptr,
+                          const LandmarkBasePtr& _landmark_other_ptr,
+                          const ProcessorBasePtr& _processor_ptr,
+                          bool _apply_loss_function,
+                          ConstraintStatus _status,
+                          StateBlockPtr _state0Ptr,
+                          StateBlockPtr _state1Ptr) :
+           ConstraintBase(_tp, _frame_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status),
+           state_ptrs_({_state0Ptr,_state1Ptr}),
+           residuals_jets_(new std::array<WolfJet, RES>),
+           jets_0_(new std::array<WolfJet, B0>),
+           jets_1_(new std::array<WolfJet, B1>)
+       {
+           // initialize jets
+           unsigned int last_jet_idx = 0;
+           for (auto i = 0; i < B0; i++)
+              (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
+           for (auto i = 0; i < B1; i++)
+              (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
+           state_ptrs_.resize(n_blocks);
+       }
+
+       virtual ~ConstraintAutodiff()
+       {
+           delete jets_0_;
+           delete jets_1_;
+           delete residuals_jets_;
+       }
+
+       virtual JacobianMethod getJacobianMethod() const
+       {
+           return JAC_AUTO;
+       }
+
+       virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const
+       {
+           // only residuals
+           if (jacobians == nullptr)
+           {
+               (*static_cast<CtrT const*>(this))(parameters[0],
+                                                 parameters[1],
+                                                 residuals);
+           }
+           // also compute jacobians
+           else
+           {
+               // update jets real part
+               std::vector<double const*> param_vec;
+               param_vec.assign(parameters,parameters+n_blocks);
+               updateJetsRealPart(param_vec);
+
+               // call functor
+               (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                                 jets_1_->data(),
+                                                 residuals_jets_->data());
+
+               // fill the residual array
+               for (auto i = 0; i < RES; i++)
+                   residuals[i] = (*residuals_jets_)[i].a;
+
+               // fill the jacobian matrices
+               for (auto i = 0; i<n_blocks; i++)
+                   if (jacobians[i] != nullptr)
+                       for (unsigned int row = 0; row < RES; row++)
+                           std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                     (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                     jacobians[i] + row * state_block_sizes_.at(i));
+           }
+           return true;
+       }
+
+       void updateJetsRealPart(const std::vector<double const*>& parameters) const
+       {
+           // update jets real part
+           for (auto i = 0; i < B0; i++)
+               (*jets_0_)[i].a = parameters[0][i];
+           for (auto i = 0; i < B1; i++)
+               (*jets_1_)[i].a = parameters[1][i];
+       }
+
+       virtual void evaluate(const std::vector<const Scalar*>& _states_ptr, Eigen::VectorXs& residual_, std::vector<Eigen::MatrixXs>& jacobians_) const
+       {
+           assert(residual_.size() == RES);
+           jacobians_.clear();
+
+           assert(_states_ptr.size() == n_blocks);
+
+           // init jacobian
+           for(auto i = 0; i < n_blocks; ++i)
+           {
+              Eigen::MatrixXs Ji = Eigen::MatrixXs::Zero(RES, state_block_sizes_[i]);
+              jacobians_.push_back(Ji);
+           }
+
+           // update jets real part
+           updateJetsRealPart(_states_ptr);
+
+           // call functor
+           (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                             jets_1_->data(),
+                                             residuals_jets_->data());
+
+           // fill the residual vector
+           for (auto i = 0; i < RES; i++)
+               residual_(i) = (*residuals_jets_)[i].a;
+
+           // fill the jacobian matrices
+           for (auto i = 0; i<n_blocks; i++)
+               if (!state_ptrs_[i]->isFixed())
+                   for (unsigned int row = 0; row < RES; row++)
+                       std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                 (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                 jacobians_[i].data() + row * state_block_sizes_.at(i));
+
+          // print jacobian matrices
+//           for (auto i = 0; i < n_blocks; i++)
+//               std::cout << jacobians_[i] << std::endl << std::endl;
+       }
+
+       virtual std::vector<Scalar*> getStateScalarPtrVector() const
+       {
+           return std::vector<Scalar*>({state_ptrs_[0]->getPtr(),
+                                        state_ptrs_[1]->getPtr()
+                                        });
+       }
+
+       virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const
+       {
+           return state_ptrs_;
+       }
+
+       virtual std::vector<unsigned int> getStateSizes() const
+       {
+           return state_block_sizes_;
+       }
+
+       virtual unsigned int getSize() const
+       {
+           return RES;
+       }
+};
+
+////////////////// SPECIALIZATION 1 BLOCK ////////////////////////////////////////////////////////////////////////
+
+template <class CtrT,unsigned int RES,unsigned int B0>
+class ConstraintAutodiff<CtrT,RES,B0,0,0,0,0,0,0,0,0,0> : public ConstraintBase
+{
+   public:
+
+       static const unsigned int residualSize = RES;
+       static const unsigned int block0Size = B0;
+       static const unsigned int block1Size = 0;
+       static const unsigned int block2Size = 0;
+       static const unsigned int block3Size = 0;
+       static const unsigned int block4Size = 0;
+       static const unsigned int block5Size = 0;
+       static const unsigned int block6Size = 0;
+       static const unsigned int block7Size = 0;
+       static const unsigned int block8Size = 0;
+       static const unsigned int block9Size = 0;
+       static const unsigned int n_blocks = 1;
+
+       static const std::vector<unsigned int> state_block_sizes_;
+
+       typedef ceres::Jet<Scalar, B0> WolfJet;
+
+   protected:
+
+       std::vector<StateBlockPtr> state_ptrs_;
+
+       static const std::vector<unsigned int> jacobian_locations_;
+       std::array<WolfJet, RES>* residuals_jets_;
+
+       std::array<WolfJet, B0>* jets_0_;
+
+   public:
+
+       ConstraintAutodiff(ConstraintType _tp,
+                          const FrameBasePtr& _frame_other_ptr,
+                          const FeatureBasePtr& _feature_other_ptr,
+                          const LandmarkBasePtr& _landmark_other_ptr,
+                          const ProcessorBasePtr& _processor_ptr,
+                          bool _apply_loss_function,
+                          ConstraintStatus _status,
+                          StateBlockPtr _state0Ptr) :
+           ConstraintBase(_tp, _frame_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status),
+           state_ptrs_({_state0Ptr}),
+           residuals_jets_(new std::array<WolfJet, RES>),
+           jets_0_(new std::array<WolfJet, B0>)
+       {
+           // initialize jets
+           unsigned int last_jet_idx = 0;
+           for (auto i = 0; i < B0; i++)
+              (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
+           state_ptrs_.resize(n_blocks);
+       }
+
+       virtual ~ConstraintAutodiff()
+       {
+           delete jets_0_;
+           delete residuals_jets_;
+       }
+
+       virtual JacobianMethod getJacobianMethod() const
+       {
+           return JAC_AUTO;
+       }
+
+       virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const
+       {
+           // only residuals
+           if (jacobians == nullptr)
+           {
+               (*static_cast<CtrT const*>(this))(parameters[0],
+                                                 residuals);
+           }
+           // also compute jacobians
+           else
+           {
+               // update jets real part
+               std::vector<double const*> param_vec;
+               param_vec.assign(parameters,parameters+n_blocks);
+               updateJetsRealPart(param_vec);
+
+               // call functor
+               (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                                 residuals_jets_->data());
+
+               // fill the residual array
+               for (auto i = 0; i < RES; i++)
+                   residuals[i] = (*residuals_jets_)[i].a;
+
+               // fill the jacobian matrices
+               for (auto i = 0; i<n_blocks; i++)
+                   if (jacobians[i] != nullptr)
+                       for (unsigned int row = 0; row < RES; row++)
+                           std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                     (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                     jacobians[i] + row * state_block_sizes_.at(i));
+           }
+           return true;
+       }
+
+       void updateJetsRealPart(const std::vector<double const*>& parameters) const
+       {
+           // update jets real part
+           for (auto i = 0; i < B0; i++)
+               (*jets_0_)[i].a = parameters[0][i];
+       }
+
+       virtual void evaluate(const std::vector<const Scalar*>& _states_ptr, Eigen::VectorXs& residual_, std::vector<Eigen::MatrixXs>& jacobians_) const
+       {
+           assert(residual_.size() == RES);
+           jacobians_.clear();
+
+           assert(_states_ptr.size() == n_blocks);
+
+           // init jacobian
+           for(auto i = 0; i < n_blocks; ++i)
+           {
+              Eigen::MatrixXs Ji = Eigen::MatrixXs::Zero(RES, state_block_sizes_[i]);
+              jacobians_.push_back(Ji);
+           }
+
+           // update jets real part
+           updateJetsRealPart(_states_ptr);
+
+           // call functor
+           (*static_cast<CtrT const*>(this))(jets_0_->data(),
+                                             residuals_jets_->data());
+
+           // fill the residual vector
+           for (auto i = 0; i < RES; i++)
+               residual_(i) = (*residuals_jets_)[i].a;
+
+           // fill the jacobian matrices
+           for (auto i = 0; i<n_blocks; i++)
+               if (!state_ptrs_[i]->isFixed())
+                   for (unsigned int row = 0; row < RES; row++)
+                       std::copy((*residuals_jets_)[row].v.data() + jacobian_locations_.at(i),
+                                 (*residuals_jets_)[row].v.data() + jacobian_locations_.at(i) + state_block_sizes_.at(i),
+                                 jacobians_[i].data() + row * state_block_sizes_.at(i));
+
+          // print jacobian matrices
+//           for (auto i = 0; i < n_blocks; i++)
+//               std::cout << jacobians_[i] << std::endl << std::endl;
+       }
+
+       virtual std::vector<Scalar*> getStateScalarPtrVector() const
+       {
+           return std::vector<Scalar*>({state_ptrs_[0]->getPtr()
+                                        });
+       }
+
+       virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const
+       {
+           return state_ptrs_;
+       }
+
+       virtual std::vector<unsigned int> getStateSizes() const
+       {
+           return state_block_sizes_;
+       }
+
+       virtual unsigned int getSize() const
+       {
+           return RES;
+       }
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                          STATIC CONST VECTORS INITIALIZATION
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// state_block_sizes_
+// 10 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8,unsigned int B9>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8,B9};
+// 9 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8};
+// 8 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7};
+// 7 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6};
+// 6 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5};
+// 5 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4};
+// 4 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3};
+// 3 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2};
+// 2 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1};
+// 1 BLOCK
+template <class CtrT,unsigned int RES,unsigned int B0>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,0,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0};
+
+// jacobian_locations_
+// 10 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8,unsigned int B9>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9>::jacobian_locations_ = {0,
+                                                                                                                   B0,
+                                                                                                                   B0+B1,
+                                                                                                                   B0+B1+B2,
+                                                                                                                   B0+B1+B2+B3,
+                                                                                                                   B0+B1+B2+B3+B4,
+                                                                                                                   B0+B1+B2+B3+B4+B5,
+                                                                                                                   B0+B1+B2+B3+B4+B5+B6,
+                                                                                                                   B0+B1+B2+B3+B4+B5+B6+B7,
+                                                                                                                   B0+B1+B2+B3+B4+B5+B6+B7+B8};
+// 9 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7,unsigned int B8>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0>::jacobian_locations_ = {0,
+                                                                                                                  B0,
+                                                                                                                  B0+B1,
+                                                                                                                  B0+B1+B2,
+                                                                                                                  B0+B1+B2+B3,
+                                                                                                                  B0+B1+B2+B3+B4,
+                                                                                                                  B0+B1+B2+B3+B4+B5,
+                                                                                                                  B0+B1+B2+B3+B4+B5+B6,
+                                                                                                                  B0+B1+B2+B3+B4+B5+B6+B7};
+// 8 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6,unsigned int B7>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0>::jacobian_locations_ = {0,
+                                                                                                                 B0,
+                                                                                                                 B0+B1,
+                                                                                                                 B0+B1+B2,
+                                                                                                                 B0+B1+B2+B3,
+                                                                                                                 B0+B1+B2+B3+B4,
+                                                                                                                 B0+B1+B2+B3+B4+B5,
+                                                                                                                 B0+B1+B2+B3+B4+B5+B6};
+// 7 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5,unsigned int B6>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0>::jacobian_locations_ = {0,
+                                                                                                                B0,
+                                                                                                                B0+B1,
+                                                                                                                B0+B1+B2,
+                                                                                                                B0+B1+B2+B3,
+                                                                                                                B0+B1+B2+B3+B4,
+                                                                                                                B0+B1+B2+B3+B4+B5};
+// 6 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0>::jacobian_locations_ = {0,
+                                                                                                               B0,
+                                                                                                               B0+B1,
+                                                                                                               B0+B1+B2,
+                                                                                                               B0+B1+B2+B3,
+                                                                                                               B0+B1+B2+B3+B4};
+// 5 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,B4,0,0,0,0,0>::jacobian_locations_ = {0,
+                                                                                                              B0,
+                                                                                                              B0+B1,
+                                                                                                              B0+B1+B2,
+                                                                                                              B0+B1+B2+B3};
+// 4 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,B3,0,0,0,0,0,0>::jacobian_locations_ = {0,
+                                                                                                             B0,
+                                                                                                             B0+B1,
+                                                                                                             B0+B1+B2};
+// 3 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,B2,0,0,0,0,0,0,0>::jacobian_locations_ = {0,
+                                                                                                            B0,
+                                                                                                            B0+B1};
+// 2 BLOCKS
+template <class CtrT,unsigned int RES,unsigned int B0,unsigned int B1>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,B1,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0,
+                                                                                                           B0};
+// 1 BLOCK
+template <class CtrT,unsigned int RES,unsigned int B0>
+const std::vector<unsigned int> ConstraintAutodiff<CtrT,RES,B0,0,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0};
+
+} // namespace wolf
+
+#endif
diff --git a/src/constraint_base.h b/src/constraint_base.h
index ba85eaef7f605dd8930b01e62b04730e919d51d0..bd5cd88f0fec4b8cfa48bcbb0c0e9692c14fefc2 100644
--- a/src/constraint_base.h
+++ b/src/constraint_base.h
@@ -59,17 +59,29 @@ class ConstraintBase : public NodeBase, public std::enable_shared_from_this<Cons
          **/
         ConstraintType getTypeId() const;
 
+        /** \brief Evaluate the constraint given the input parameters and returning the residuals and jacobians
+        **/
+        virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const = 0;
+
+        /** Returns a vector of Jacobian matrix corresponding to each state block evaluated in the point provided in _states_ptr and the residual vector
+         **/
+        virtual void evaluate(const std::vector<const Scalar*>& _states_ptr, Eigen::VectorXs& residual_, std::vector<Eigen::MatrixXs>& jacobians_) const = 0;
+
         /** \brief Returns the jacobians computation method
          **/
         virtual JacobianMethod getJacobianMethod() const = 0;
 
         /** \brief Returns a vector of scalar pointers to the first element of all state blocks involved in the constraint
          **/
-        virtual const std::vector<Scalar*> getStateScalarPtrVector() = 0;
+        virtual std::vector<Scalar*> getStateScalarPtrVector() const = 0;
 
         /** \brief Returns a vector of pointers to the states in which this constraint depends
          **/
-        virtual const std::vector<StateBlockPtr> getStateBlockPtrVector() const = 0;
+        virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const = 0;
+
+        /** \brief Returns a vector of the states sizes
+         **/
+        virtual std::vector<unsigned int> getStateSizes() const = 0;
 
         /** \brief Returns a reference to the feature measurement
          **/
diff --git a/src/constraint_container.h b/src/constraint_container.h
index 41f7f3f3a93a56cc2f580a30107add1192de3964..7ec89a5a791810ddfb275d0b19dd6238a142d1d7 100644
--- a/src/constraint_container.h
+++ b/src/constraint_container.h
@@ -3,14 +3,14 @@
 
 //Wolf includes
 #include "wolf.h"
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 #include "landmark_container.h"
 
 namespace wolf {
     
 WOLF_PTR_TYPEDEFS(ConstraintContainer);
 
-class ConstraintContainer: public ConstraintSparse<3,2,1,2,1>
+class ConstraintContainer: public ConstraintAutodiff<ConstraintContainer,3,2,1,2,1>
 {
 	protected:
 		LandmarkContainerWPtr lmk_ptr_;
@@ -23,7 +23,7 @@ class ConstraintContainer: public ConstraintSparse<3,2,1,2,1>
                           const ProcessorBasePtr& _processor_ptr,
                           const unsigned int _corner,
                           bool _apply_loss_function = false, ConstraintStatus _status = CTR_ACTIVE) :
-      ConstraintSparse<3,2,1,2,1>(CTR_CONTAINER, nullptr, nullptr, _lmk_ptr, _processor_ptr, _apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr(),_ftr_ptr->getFramePtr()->getOPtr(), _lmk_ptr->getPPtr(), _lmk_ptr->getOPtr()),
+            ConstraintAutodiff<ConstraintContainer,3,2,1,2,1>(CTR_CONTAINER, nullptr, nullptr, _lmk_ptr, _processor_ptr, _apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr(),_ftr_ptr->getFramePtr()->getOPtr(), _lmk_ptr->getPPtr(), _lmk_ptr->getOPtr()),
 			lmk_ptr_(_lmk_ptr),
 			corner_(_corner)
 		{
diff --git a/src/constraint_corner_2D.h b/src/constraint_corner_2D.h
index 6a5ea8a06aa76d3523dfcacfea4acc542578df9d..d3702dc58bf17dc250f6c5687a4422eb07829eb7 100644
--- a/src/constraint_corner_2D.h
+++ b/src/constraint_corner_2D.h
@@ -2,14 +2,14 @@
 #define CONSTRAINT_CORNER_2D_THETA_H_
 
 //Wolf includes
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 #include "landmark_corner_2D.h"
 
 namespace wolf {
 
 WOLF_PTR_TYPEDEFS(ConstraintCorner2D);
     
-class ConstraintCorner2D: public ConstraintSparse<3,2,1,2,1>
+class ConstraintCorner2D: public ConstraintAutodiff<ConstraintCorner2D, 3,2,1,2,1>
 {
 	public:
 
@@ -18,7 +18,7 @@ class ConstraintCorner2D: public ConstraintSparse<3,2,1,2,1>
                        const ProcessorBasePtr& _processor_ptr,
                        bool _apply_loss_function = false,
                        ConstraintStatus _status = CTR_ACTIVE) :
-      ConstraintSparse<3,2,1,2,1>(CTR_CORNER_2D, nullptr, nullptr, _lmk_ptr, _processor_ptr, _apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr(),_ftr_ptr->getFramePtr()->getOPtr(), _lmk_ptr->getPPtr(), _lmk_ptr->getOPtr())
+        ConstraintAutodiff<ConstraintCorner2D,3,2,1,2,1>(CTR_CORNER_2D, nullptr, nullptr, _lmk_ptr, _processor_ptr, _apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr(),_ftr_ptr->getFramePtr()->getOPtr(), _lmk_ptr->getPPtr(), _lmk_ptr->getOPtr())
     {
       setType("CORNER 2D");
     }
@@ -35,16 +35,15 @@ class ConstraintCorner2D: public ConstraintSparse<3,2,1,2,1>
                      const T* const _landmarkO, T* _residuals) const;
 
     /** \brief Returns the jacobians computation method
-         *
-         * Returns the jacobians computation method
-         *
-         **/
+     *
+     * Returns the jacobians computation method
+     *
+     **/
     virtual JacobianMethod getJacobianMethod() const override
     {
       return JAC_AUTO;
     }
 
-public:
     static ConstraintBasePtr create(const FeatureBasePtr& _feature_ptr, const NodeBasePtr& _correspondant_ptr, const ProcessorBasePtr& _processor_ptr = nullptr)
     {
       return std::make_shared<ConstraintCorner2D>(_feature_ptr, std::static_pointer_cast<LandmarkCorner2D>(_correspondant_ptr), _processor_ptr);
diff --git a/src/constraint_epipolar.h b/src/constraint_epipolar.h
index 199888a9a2751c428e4102cc77ec6a14b69f7f76..bb6d1f86f074ed913a583ee7cc3e322780b497e5 100644
--- a/src/constraint_epipolar.h
+++ b/src/constraint_epipolar.h
@@ -19,22 +19,34 @@ class ConstraintEpipolar : public ConstraintBase
 
         virtual ~ConstraintEpipolar() = default;
 
+
+        /** \brief Evaluate the constraint given the input parameters and returning the residuals and jacobians
+        **/
+        virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const{return true;};
+
+        /** Returns a residual vector and a vector of Jacobian matrix corresponding to each state block evaluated in the point provided in _states_ptr
+         **/
+        virtual void evaluate(const std::vector<const Scalar*>& _states_ptr, Eigen::VectorXs& residual_, std::vector<Eigen::MatrixXs>& jacobians_) const{};
         /** \brief Returns the jacobians computation method
          **/
         virtual JacobianMethod getJacobianMethod() const override {return JAC_ANALYTIC;}
 
         /** \brief Returns a vector of scalar pointers to the first element of all state blocks involved in the constraint
          **/
-        virtual const std::vector<Scalar*> getStateScalarPtrVector() override {return std::vector<Scalar*>(0);}
+        virtual std::vector<Scalar*> getStateScalarPtrVector() const override {return std::vector<Scalar*>(0);}
 
         /** \brief Returns a vector of pointers to the states in which this constraint depends
          **/
-        virtual const std::vector<StateBlockPtr> getStateBlockPtrVector() const override {return std::vector<StateBlockPtr>(0);}
+        virtual std::vector<StateBlockPtr> getStateBlockPtrVector() const override {return std::vector<StateBlockPtr>(0);}
 
         /** \brief Returns the constraint residual size
          **/
         virtual unsigned int getSize() const override {return 0;}
 
+        /** \brief Returns the constraint states sizes
+         **/
+        virtual std::vector<unsigned int> getStateSizes() const{return std::vector<unsigned int>({1});}
+
     public:
         static wolf::ConstraintBasePtr create(const FeatureBasePtr& _feature_ptr,
                                               const NodeBasePtr& _correspondant_ptr,
diff --git a/src/constraint_fix.h b/src/constraint_fix.h
index 77bfe34330a429f5f660f658647674e8cb33f1bc..8b140749947b8b88007d193150a63ede0d7d5eab 100644
--- a/src/constraint_fix.h
+++ b/src/constraint_fix.h
@@ -3,7 +3,7 @@
 #define CONSTRAINT_FIX_H_
 
 //Wolf includes
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 #include "frame_base.h"
 #include "rotations.h"
 
@@ -15,12 +15,11 @@ namespace wolf {
 WOLF_PTR_TYPEDEFS(ConstraintFix);
 
 //class
-class ConstraintFix: public ConstraintSparse<3,2,1>
+class ConstraintFix: public ConstraintAutodiff<ConstraintFix,3,2,1>
 {
     public:
         ConstraintFix(FeatureBasePtr _ftr_ptr, bool _apply_loss_function = false, ConstraintStatus _status = CTR_ACTIVE) :
-                ConstraintSparse<3, 2, 1>(CTR_FIX, _apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr(),
-                                          _ftr_ptr->getFramePtr()->getOPtr())
+                ConstraintAutodiff<ConstraintFix, 3, 2, 1>(CTR_FIX, nullptr, nullptr, nullptr, nullptr,_apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr(), _ftr_ptr->getFramePtr()->getOPtr())
         {
             setType("FIX");
 //            std::cout << "created ConstraintFix " << std::endl;
diff --git a/src/constraint_fix_3D.h b/src/constraint_fix_3D.h
index bd5cb3750984c4d56535b338db339bfc96d44f31..b64f63e699a6501543a7fdbd74c323e00a0c460e 100644
--- a/src/constraint_fix_3D.h
+++ b/src/constraint_fix_3D.h
@@ -3,7 +3,7 @@
 #define CONSTRAINT_FIX_3D_H_
 
 //Wolf includes
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 #include "frame_base.h"
 #include "rotations.h"
 
@@ -13,13 +13,12 @@ namespace wolf {
 WOLF_PTR_TYPEDEFS(ConstraintFix3D);
 
 //class
-class ConstraintFix3D: public ConstraintSparse<6,3,4>
+class ConstraintFix3D: public ConstraintAutodiff<ConstraintFix3D,6,3,4>
 {
     public:
 
         ConstraintFix3D(FeatureBasePtr _ftr_ptr, bool _apply_loss_function = false, ConstraintStatus _status = CTR_ACTIVE) :
-                ConstraintSparse<6,3,4>(CTR_FIX_3D, _apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr(),
-                                          _ftr_ptr->getFramePtr()->getOPtr())
+            ConstraintAutodiff<ConstraintFix3D,6,3,4>(CTR_FIX_3D, nullptr, nullptr, nullptr, nullptr, _apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr(), _ftr_ptr->getFramePtr()->getOPtr())
         {
             setType("FIX3D");
         }
diff --git a/src/constraint_fix_bias.h b/src/constraint_fix_bias.h
index 3ccdc2377e45f96de99016ae02380ea1ba50966f..6afa4adc69435469cbdf3a8b3e0279164cc711d1 100644
--- a/src/constraint_fix_bias.h
+++ b/src/constraint_fix_bias.h
@@ -3,7 +3,7 @@
 #define CONSTRAINT_FIX_BIAS_H_
 
 //Wolf includes
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 #include "frame_base.h"
 #include "frame_imu.h"
 #include "rotations.h"
@@ -17,11 +17,11 @@ namespace wolf {
 WOLF_PTR_TYPEDEFS(ConstraintFixBias);
 
 //class
-class ConstraintFixBias: public ConstraintSparse<6,3,3>
+class ConstraintFixBias: public ConstraintAutodiff<ConstraintFixBias,6,3,3>
 {
     public:
         ConstraintFixBias(FeatureBasePtr _ftr_ptr, bool _apply_loss_function = false, ConstraintStatus _status = CTR_ACTIVE) :
-                ConstraintSparse<6, 3, 3>(CTR_FIX_BIAS, _apply_loss_function, _status, std::static_pointer_cast<FrameIMU>(_ftr_ptr->getFramePtr())->getAccBiasPtr(),
+                ConstraintAutodiff<ConstraintFixBias, 6, 3, 3>(CTR_FIX_BIAS, nullptr, nullptr, nullptr, nullptr, _apply_loss_function, _status, std::static_pointer_cast<FrameIMU>(_ftr_ptr->getFramePtr())->getAccBiasPtr(),
                                           std::static_pointer_cast<FrameIMU>(_ftr_ptr->getFramePtr())->getGyroBiasPtr())
         {
             setType("FIX BIAS");
diff --git a/src/constraint_gps_2D.h b/src/constraint_gps_2D.h
index 874cba0f5271ab046af4e651c28d9594eb450c59..6a5948efb83027c2512c5be221d43f87c0829d69 100644
--- a/src/constraint_gps_2D.h
+++ b/src/constraint_gps_2D.h
@@ -4,19 +4,19 @@
 
 //Wolf includes
 #include "wolf.h"
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 #include "frame_base.h"
 
 namespace wolf {
     
 WOLF_PTR_TYPEDEFS(ConstraintGPS2D);
 
-class ConstraintGPS2D : public ConstraintSparse<2, 2>
+class ConstraintGPS2D : public ConstraintAutodiff<ConstraintGPS2D, 2, 2>
 {
     public:
 
         ConstraintGPS2D(FeatureBasePtr _ftr_ptr, bool _apply_loss_function = false, ConstraintStatus _status = CTR_ACTIVE) :
-                ConstraintSparse<2, 2>(CTR_GPS_FIX_2D, _apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr())
+            ConstraintAutodiff<ConstraintGPS2D, 2, 2>(CTR_GPS_FIX_2D, nullptr, nullptr, nullptr, nullptr, _apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr())
         {
             setType("GPS FIX 2D");
         }
diff --git a/src/constraint_gps_pseudorange_2D.h b/src/constraint_gps_pseudorange_2D.h
index 409dc35699f5e10a1dbe2c7702fb8106e9b0b2b6..0873355892d0d82b74c78a98fe238bbda034a2df 100644
--- a/src/constraint_gps_pseudorange_2D.h
+++ b/src/constraint_gps_pseudorange_2D.h
@@ -6,7 +6,7 @@
 //Wolf includes
 #include "sensor_gps.h"
 #include "feature_gps_pseudorange.h"
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 
 //std
 #include <string>
@@ -24,13 +24,13 @@ WOLF_PTR_TYPEDEFS(ConstraintGPSPseudorange2D);
  *
  * TODO maybe is no more true
  */
-class ConstraintGPSPseudorange2D : public ConstraintSparse<1, 2, 1, 3, 1, 3, 1>
+class ConstraintGPSPseudorange2D : public ConstraintAutodiff<ConstraintGPSPseudorange2D, 1, 2, 1, 3, 1, 3, 1>
 {
     public:
         ConstraintGPSPseudorange2D(const FeatureBasePtr& _ftr_ptr,
                                    bool _apply_loss_function = false, 
                                    ConstraintStatus _status = CTR_ACTIVE) :
-            ConstraintSparse<1, 2, 1, 3, 1, 3, 1>(CTR_GPS_PR_2D,
+           ConstraintAutodiff<ConstraintGPSPseudorange2D, 1, 2, 1, 3, 1, 3, 1>(CTR_GPS_PR_2D,
                                                   _apply_loss_function,
                                                   _status,
                                                   _ftr_ptr->getFramePtr()->getPPtr(), // position of the vehicle's frame with respect to the initial pos frame
diff --git a/src/constraint_gps_pseudorange_3D.h b/src/constraint_gps_pseudorange_3D.h
index c87cb87933717f9ef30fc25097e012982710afa7..47e4d95ffc0a263ec2215742e473efa3165fac4d 100644
--- a/src/constraint_gps_pseudorange_3D.h
+++ b/src/constraint_gps_pseudorange_3D.h
@@ -6,7 +6,7 @@
 //Wolf includes
 #include "sensor_gps.h"
 #include "feature_gps_pseudorange.h"
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 
 namespace wolf {
 
@@ -21,7 +21,7 @@ WOLF_PTR_TYPEDEFS(ConstraintGPSPseudorange3D);
  *
  * TODO maybe is no more true
  */
-class ConstraintGPSPseudorange3D: public ConstraintSparse<1, 3, 4, 3, 1, 3, 4>
+class ConstraintGPSPseudorange3D: public ConstraintAutodiff<ConstraintGPSPseudorange3D, 1, 3, 4, 3, 1, 3, 4>
 {
 
     public:
@@ -29,7 +29,7 @@ class ConstraintGPSPseudorange3D: public ConstraintSparse<1, 3, 4, 3, 1, 3, 4>
         ConstraintGPSPseudorange3D(FeatureBasePtr _ftr_ptr, 
                                    bool _apply_loss_function = false, 
                                    ConstraintStatus _status = CTR_ACTIVE) :
-            ConstraintSparse<1, 3, 4, 3, 1, 3, 4>(CTR_GPS_PR_3D, _apply_loss_function, _status,
+             ConstraintAutodiff<ConstraintGPSPseudorange3D, 1, 3, 4, 3, 1, 3, 4>(CTR_GPS_PR_3D, nullptr, nullptr, nullptr, _apply_loss_function, _status,
                             _ftr_ptr->getFramePtr()->getPPtr(), // position of the vehicle's frame with respect to map frame
                             _ftr_ptr->getFramePtr()->getOPtr(), // orientation of the vehicle's frame wrt map frame
                             _ftr_ptr->getCapturePtr()->getSensorPPtr(), // position of the sensor (gps antenna) with respect to base frame
diff --git a/src/constraint_imu.h b/src/constraint_imu.h
index 7ae0c07b7408ff6dbdb86d88a137ae39cb33ce07..2a21202a2a8f38c3fc47342cdd244ed10b6a61a6 100644
--- a/src/constraint_imu.h
+++ b/src/constraint_imu.h
@@ -2,7 +2,7 @@
 #define CONSTRAINT_IMU_THETA_H_
 
 //Wolf includes
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 #include "feature_imu.h"
 #include "frame_imu.h"
 #include "sensor_imu.h"
@@ -16,7 +16,7 @@ namespace wolf {
 WOLF_PTR_TYPEDEFS(ConstraintIMU);
 
 //class
-class ConstraintIMU : public ConstraintSparse<15, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3>
+class ConstraintIMU : public ConstraintAutodiff<ConstraintIMU, 15, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3>
 {
     public:
         ConstraintIMU(const FeatureIMUPtr& _ftr_ptr, const FrameIMUPtr& _frame_ptr,
@@ -145,7 +145,7 @@ inline ConstraintIMU::ConstraintIMU(const FeatureIMUPtr& _ftr_ptr,
                                     const FrameIMUPtr& _frame_ptr,
                                     const ProcessorBasePtr& _processor_ptr,
                                     bool _apply_loss_function, ConstraintStatus _status) :
-        ConstraintSparse<15, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3>(CTR_IMU, _frame_ptr, nullptr, nullptr, _processor_ptr, _apply_loss_function, _status,
+        ConstraintAutodiff<ConstraintIMU,15, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3>(CTR_IMU, _frame_ptr, nullptr, nullptr, _processor_ptr, _apply_loss_function, _status,
                                                     _frame_ptr->getPPtr(), _frame_ptr->getOPtr(), _frame_ptr->getVPtr(),
                                                     _frame_ptr->getAccBiasPtr(), _frame_ptr->getGyroBiasPtr(),
                                                     _ftr_ptr->getFramePtr()->getPPtr(),
diff --git a/src/constraint_odom_2D.h b/src/constraint_odom_2D.h
index 2314f9179d774c7f582889c8b69a463490afff9d..e592e322eea96a477d402816203f5e2140ec8c86 100644
--- a/src/constraint_odom_2D.h
+++ b/src/constraint_odom_2D.h
@@ -2,7 +2,7 @@
 #define CONSTRAINT_ODOM_2D_THETA_H_
 
 //Wolf includes
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 #include "frame_base.h"
 
 //#include "ceres/jet.h"
@@ -10,16 +10,16 @@
 namespace wolf {
     
 WOLF_PTR_TYPEDEFS(ConstraintOdom2D);
-    
+
 //class
-class ConstraintOdom2D : public ConstraintSparse<3, 2, 1, 2, 1>
+class ConstraintOdom2D : public ConstraintAutodiff<ConstraintOdom2D, 3, 2, 1, 2, 1>
 {
     public:
         ConstraintOdom2D(const FeatureBasePtr& _ftr_ptr,
                          const FrameBasePtr& _frame_ptr,
                          const ProcessorBasePtr& _processor_ptr = nullptr,
                          bool _apply_loss_function = false, ConstraintStatus _status = CTR_ACTIVE) :
-                ConstraintSparse<3, 2, 1, 2, 1>(CTR_ODOM_2D, _frame_ptr, nullptr, nullptr, _processor_ptr, _apply_loss_function, _status, _frame_ptr->getPPtr(), _frame_ptr->getOPtr(), _ftr_ptr->getFramePtr()->getPPtr(), _ftr_ptr->getFramePtr()->getOPtr())
+             ConstraintAutodiff<ConstraintOdom2D, 3, 2, 1, 2, 1>(CTR_ODOM_2D, _frame_ptr, nullptr, nullptr, _processor_ptr, _apply_loss_function, _status, _frame_ptr->getPPtr(), _frame_ptr->getOPtr(), _ftr_ptr->getFramePtr()->getPPtr(), _ftr_ptr->getFramePtr()->getOPtr())
         {
             setType("ODOM 2D");
 //            std::cout << "created ConstraintOdom2D " << std::endl;
diff --git a/src/constraint_odom_3D.h b/src/constraint_odom_3D.h
index 2062bbba75e10762a694637977df63ade038bee6..e315489b89a5196323b3837cfc9611295b2ecb6e 100644
--- a/src/constraint_odom_3D.h
+++ b/src/constraint_odom_3D.h
@@ -8,7 +8,7 @@
 #ifndef CONSTRAINT_ODOM_3D_H_
 #define CONSTRAINT_ODOM_3D_H_
 
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 #include "rotations.h"
 
 namespace wolf
@@ -17,7 +17,7 @@ namespace wolf
 WOLF_PTR_TYPEDEFS(ConstraintOdom3D);
     
 //class
-class ConstraintOdom3D : public ConstraintSparse<6,3,4,3,4>
+class ConstraintOdom3D : public ConstraintAutodiff<ConstraintOdom3D,6,3,4,3,4>
 {
     public:
         ConstraintOdom3D(const FeatureBasePtr& _ftr_current_ptr,
@@ -79,7 +79,7 @@ inline ConstraintOdom3D::ConstraintOdom3D(const FeatureBasePtr& _ftr_current_ptr
                                           const ProcessorBasePtr& _processor_ptr,
                                           bool _apply_loss_function,
                                           ConstraintStatus _status) :
-        ConstraintSparse<6, 3, 4, 3, 4>(CTR_ODOM_3D,        // type
+        ConstraintAutodiff<ConstraintOdom3D, 6, 3, 4, 3, 4>(CTR_ODOM_3D,        // type
                                         _frame_past_ptr,    // frame other
                                         nullptr,            // feature other
                                         nullptr,            // landmark other
diff --git a/src/constraint_point_2D.h b/src/constraint_point_2D.h
index 9a092e1e045d96839e2c7ccaf02bda706cba2262..927743721fe640149df46d3a47931a4b1a7645dd 100644
--- a/src/constraint_point_2D.h
+++ b/src/constraint_point_2D.h
@@ -2,7 +2,7 @@
 #define CONSTRAINT_POINT_2D_THETA_H_
 
 //Wolf includes
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 #include "feature_polyline_2D.h"
 #include "landmark_polyline_2D.h"
 
@@ -13,7 +13,7 @@ WOLF_PTR_TYPEDEFS(ConstraintPoint2D);
 /**
  * @brief The ConstraintPoint2D class
  */
-class ConstraintPoint2D: public ConstraintSparse<2,2,1,2,1,2>
+class ConstraintPoint2D: public ConstraintAutodiff<ConstraintPoint2D, 2,2,1,2,1,2>
 {
     protected:
         unsigned int feature_point_id_;
@@ -29,16 +29,16 @@ class ConstraintPoint2D: public ConstraintSparse<2,2,1,2,1,2>
                       const LandmarkPolyline2DPtr& _lmk_ptr,
                       const ProcessorBasePtr& _processor_ptr,
                       unsigned int _ftr_point_id, int _lmk_point_id, bool _apply_loss_function = false, ConstraintStatus _status = CTR_ACTIVE) :
-      ConstraintSparse<2,2,1,2,1,2>(CTR_POINT_2D, nullptr, nullptr, _lmk_ptr, _processor_ptr, _apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr(), _ftr_ptr->getFramePtr()->getOPtr(), _lmk_ptr->getPPtr(), _lmk_ptr->getOPtr(), _lmk_ptr->getPointStateBlockPtr(_lmk_point_id)),
-			feature_point_id_(_ftr_point_id), landmark_point_id_(_lmk_point_id), point_state_ptr_(_lmk_ptr->getPointStateBlockPtr(_lmk_point_id)), measurement_(_ftr_ptr->getPoints().col(_ftr_point_id)), measurement_covariance_(_ftr_ptr->getPointsCov().middleCols(_ftr_point_id*2,2))
-		{
-			//std::cout << "Constriant point: feature " << _ftr_ptr->id() << " landmark " << _lmk_ptr->id() << "(point " << _lmk_point_id << ")" << std::endl;
-			//std::cout << "landmark state block " << _lmk_ptr->getPointStateBlockPtr(_lmk_point_id)->getVector().transpose() << std::endl;
-            setType("POINT TO POINT 2D");
-            Eigen::LLT<Eigen::MatrixXs> lltOfA(measurement_covariance_); // compute the Cholesky decomposition of A
-            Eigen::MatrixXs measurement_sqrt_covariance = lltOfA.matrixU();
-            measurement_sqrt_information_ = measurement_sqrt_covariance.inverse().transpose(); // retrieve factor U  in the decomposition
-		}
+        ConstraintAutodiff<ConstraintPoint2D,2,2,1,2,1,2>(CTR_POINT_2D, nullptr, nullptr, _lmk_ptr, _processor_ptr, _apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr(), _ftr_ptr->getFramePtr()->getOPtr(), _lmk_ptr->getPPtr(), _lmk_ptr->getOPtr(), _lmk_ptr->getPointStateBlockPtr(_lmk_point_id)),
+        feature_point_id_(_ftr_point_id), landmark_point_id_(_lmk_point_id), point_state_ptr_(_lmk_ptr->getPointStateBlockPtr(_lmk_point_id)), measurement_(_ftr_ptr->getPoints().col(_ftr_point_id)), measurement_covariance_(_ftr_ptr->getPointsCov().middleCols(_ftr_point_id*2,2))
+    {
+        //std::cout << "Constriant point: feature " << _ftr_ptr->id() << " landmark " << _lmk_ptr->id() << "(point " << _lmk_point_id << ")" << std::endl;
+        //std::cout << "landmark state block " << _lmk_ptr->getPointStateBlockPtr(_lmk_point_id)->getVector().transpose() << std::endl;
+        setType("POINT TO POINT 2D");
+        Eigen::LLT<Eigen::MatrixXs> lltOfA(measurement_covariance_); // compute the Cholesky decomposition of A
+        Eigen::MatrixXs measurement_sqrt_covariance = lltOfA.matrixU();
+        measurement_sqrt_information_ = measurement_sqrt_covariance.inverse().transpose(); // retrieve factor U  in the decomposition
+    }
 
     virtual ~ConstraintPoint2D() = default;
 
@@ -47,9 +47,9 @@ class ConstraintPoint2D: public ConstraintSparse<2,2,1,2,1,2>
      * @return
      */
     LandmarkPolyline2DPtr getLandmarkPtr()
-		{
-			return std::static_pointer_cast<LandmarkPolyline2D>(landmark_other_ptr_.lock());
-		}
+    {
+        return std::static_pointer_cast<LandmarkPolyline2D>(landmark_other_ptr_.lock());
+    }
 
     /**
      * @brief getLandmarkPointId
diff --git a/src/constraint_point_to_line_2D.h b/src/constraint_point_to_line_2D.h
index 55eb97f4d5e9f04707f5447a839fc5a93da7d53a..c54b6ae50cb63ca1723817d688571bedd7f1f960 100644
--- a/src/constraint_point_to_line_2D.h
+++ b/src/constraint_point_to_line_2D.h
@@ -2,7 +2,7 @@
 #define CONSTRAINT_POINT_TO_LINE_2D_H_
 
 //Wolf includes
-#include "constraint_sparse.h"
+#include "constraint_autodiff.h"
 #include "feature_polyline_2D.h"
 #include "landmark_polyline_2D.h"
 
@@ -11,7 +11,7 @@ namespace wolf {
 WOLF_PTR_TYPEDEFS(ConstraintPointToLine2D);
     
 //class
-class ConstraintPointToLine2D: public ConstraintSparse<1,2,1,2,1,2,2>
+class ConstraintPointToLine2D: public ConstraintAutodiff<ConstraintPointToLine2D, 1,2,1,2,1,2,2>
 {
     protected:
 		int landmark_point_id_;
@@ -30,15 +30,15 @@ class ConstraintPointToLine2D: public ConstraintSparse<1,2,1,2,1,2,2>
                             const ProcessorBasePtr& _processor_ptr,
                             unsigned int _ftr_point_id, int _lmk_point_id,  int _lmk_point_aux_id,
                             bool _apply_loss_function = false, ConstraintStatus _status = CTR_ACTIVE) :
-      ConstraintSparse<1,2,1,2,1,2,2>(CTR_POINT_TO_LINE_2D, nullptr, nullptr, _lmk_ptr, _processor_ptr, _apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr(), _ftr_ptr->getFramePtr()->getOPtr(), _lmk_ptr->getPPtr(), _lmk_ptr->getOPtr(), _lmk_ptr->getPointStateBlockPtr(_lmk_point_id), _lmk_ptr->getPointStateBlockPtr(_lmk_point_aux_id)),
-			landmark_point_id_(_lmk_point_id), landmark_point_aux_id_(_lmk_point_aux_id), feature_point_id_(_ftr_point_id), point_state_ptr_(_lmk_ptr->getPointStateBlockPtr(_lmk_point_id)), point_aux_state_ptr_(_lmk_ptr->getPointStateBlockPtr(_lmk_point_aux_id)), measurement_(_ftr_ptr->getPoints().col(_ftr_point_id)), measurement_covariance_(_ftr_ptr->getPointsCov().middleCols(_ftr_point_id*2,2))
-		{
-			//std::cout << "ConstraintPointToLine2D" << std::endl;
-            setType("POINT TO LINE 2D");
-            Eigen::LLT<Eigen::MatrixXs> lltOfA(measurement_covariance_); // compute the Cholesky decomposition of A
-            Eigen::MatrixXs measurement_sqrt_covariance = lltOfA.matrixU();
-            measurement_sqrt_information_ = measurement_sqrt_covariance.inverse().transpose(); // retrieve factor U  in the decomposition
-		}
+        ConstraintAutodiff<ConstraintPointToLine2D, 1,2,1,2,1,2,2>(CTR_POINT_TO_LINE_2D, nullptr, nullptr, _lmk_ptr, _processor_ptr, _apply_loss_function, _status, _ftr_ptr->getFramePtr()->getPPtr(), _ftr_ptr->getFramePtr()->getOPtr(), _lmk_ptr->getPPtr(), _lmk_ptr->getOPtr(), _lmk_ptr->getPointStateBlockPtr(_lmk_point_id), _lmk_ptr->getPointStateBlockPtr(_lmk_point_aux_id)),
+        landmark_point_id_(_lmk_point_id), landmark_point_aux_id_(_lmk_point_aux_id), feature_point_id_(_ftr_point_id), point_state_ptr_(_lmk_ptr->getPointStateBlockPtr(_lmk_point_id)), point_aux_state_ptr_(_lmk_ptr->getPointStateBlockPtr(_lmk_point_aux_id)), measurement_(_ftr_ptr->getPoints().col(_ftr_point_id)), measurement_covariance_(_ftr_ptr->getPointsCov().middleCols(_ftr_point_id*2,2))
+    {
+        //std::cout << "ConstraintPointToLine2D" << std::endl;
+        setType("POINT TO LINE 2D");
+        Eigen::LLT<Eigen::MatrixXs> lltOfA(measurement_covariance_); // compute the Cholesky decomposition of A
+        Eigen::MatrixXs measurement_sqrt_covariance = lltOfA.matrixU();
+        measurement_sqrt_information_ = measurement_sqrt_covariance.inverse().transpose(); // retrieve factor U  in the decomposition
+    }
 
     virtual ~ConstraintPointToLine2D() = default;
 
diff --git a/src/constraint_sparse.h b/src/constraint_sparse.h
deleted file mode 100644
index 3ba6ecac2a267d09c6dc7826b853f5c9456c8682..0000000000000000000000000000000000000000
--- a/src/constraint_sparse.h
+++ /dev/null
@@ -1,410 +0,0 @@
-
-#ifndef CONSTRAINT_SPARSE_H_
-#define CONSTRAINT_SPARSE_H_
-
-//Wolf includes
-#include "constraint_base.h"
-#include "state_block.h"
-
-namespace wolf {
-
-//TODO: change class name (and file name!->includes) to ConstraintNumericalAutoDiff 
-//template class ConstraintSparse
-template <const unsigned int RESIDUAL_SIZE,
-                unsigned int BLOCK_0_SIZE,
-                unsigned int BLOCK_1_SIZE = 0,
-                unsigned int BLOCK_2_SIZE = 0,
-                unsigned int BLOCK_3_SIZE = 0,
-                unsigned int BLOCK_4_SIZE = 0,
-                unsigned int BLOCK_5_SIZE = 0,
-                unsigned int BLOCK_6_SIZE = 0,
-                unsigned int BLOCK_7_SIZE = 0,
-                unsigned int BLOCK_8_SIZE = 0,
-                unsigned int BLOCK_9_SIZE = 0>
-class ConstraintSparse: public ConstraintBase
-{
-    protected:
-        std::vector<StateBlockPtr> state_ptr_vector_;
-        std::vector<unsigned int> state_block_sizes_vector_;
-
-    public:
-        static const unsigned int residualSize = RESIDUAL_SIZE;
-        static const unsigned int block0Size = BLOCK_0_SIZE;
-        static const unsigned int block1Size = BLOCK_1_SIZE;
-        static const unsigned int block2Size = BLOCK_2_SIZE;
-        static const unsigned int block3Size = BLOCK_3_SIZE;
-        static const unsigned int block4Size = BLOCK_4_SIZE;
-        static const unsigned int block5Size = BLOCK_5_SIZE;
-        static const unsigned int block6Size = BLOCK_6_SIZE;
-        static const unsigned int block7Size = BLOCK_7_SIZE;
-        static const unsigned int block8Size = BLOCK_8_SIZE;
-        static const unsigned int block9Size = BLOCK_9_SIZE;
-
-        /** \brief Constructor of category ABSOLUTE
-         *
-         * Constructor of category ABSOLUTE
-         *
-         **/
-        ConstraintSparse(ConstraintType _tp, bool _apply_loss_function, ConstraintStatus _status,
-                         StateBlockPtr _state0Ptr,
-                         StateBlockPtr _state1Ptr = nullptr,
-                         StateBlockPtr _state2Ptr = nullptr,
-                         StateBlockPtr _state3Ptr = nullptr,
-                         StateBlockPtr _state4Ptr = nullptr,
-                         StateBlockPtr _state5Ptr = nullptr,
-                         StateBlockPtr _state6Ptr = nullptr,
-                         StateBlockPtr _state7Ptr = nullptr,
-                         StateBlockPtr _state8Ptr = nullptr,
-                         StateBlockPtr _state9Ptr = nullptr ) ;
-
-        /** \brief Constructor valid for all categories (FRAME, FEATURE, LANDMARK)
-         **/
-        ConstraintSparse(ConstraintType _tp,
-                         const FrameBasePtr& _frame_other_ptr, const FeatureBasePtr& _feature_other_ptr,
-                         const LandmarkBasePtr& _landmark_other_ptr,
-                         const ProcessorBasePtr& _processor_ptr,
-                         bool _apply_loss_function, ConstraintStatus _status,
-                         StateBlockPtr _state0Ptr,
-                         StateBlockPtr _state1Ptr = nullptr,
-                         StateBlockPtr _state2Ptr = nullptr,
-                         StateBlockPtr _state3Ptr = nullptr,
-                         StateBlockPtr _state4Ptr = nullptr,
-                         StateBlockPtr _state5Ptr = nullptr,
-                         StateBlockPtr _state6Ptr = nullptr,
-                         StateBlockPtr _state7Ptr = nullptr,
-                         StateBlockPtr _state8Ptr = nullptr,
-                         StateBlockPtr _state9Ptr = nullptr );
-
-        virtual ~ConstraintSparse() = default;
-
-        /** \brief Returns a vector of pointers to the state blocks
-         *
-         * Returns a vector of pointers to the state blocks in which this constraint depends
-         *
-         **/
-        virtual const std::vector<Scalar*> getStateScalarPtrVector() override;
-
-        /** \brief Returns a vector of pointers to the states
-         *
-         * Returns a vector of pointers to the state in which this constraint depends
-         *
-         **/
-        virtual const std::vector<StateBlockPtr> getStateBlockPtrVector() const override;
-
-        /** \brief Returns the residual size
-         *
-         * Returns the residual size
-         *
-         **/
-        virtual unsigned int getSize() const override;
-
-    private:
-        void resizeVectors();
-};
-
-
-//////////////////////////////////////////
-//          IMPLEMENTATION
-//////////////////////////////////////////
-template <const unsigned int RESIDUAL_SIZE,
-                unsigned int BLOCK_0_SIZE,
-                unsigned int BLOCK_1_SIZE,
-                unsigned int BLOCK_2_SIZE,
-                unsigned int BLOCK_3_SIZE,
-                unsigned int BLOCK_4_SIZE,
-                unsigned int BLOCK_5_SIZE,
-                unsigned int BLOCK_6_SIZE,
-                unsigned int BLOCK_7_SIZE,
-                unsigned int BLOCK_8_SIZE,
-                unsigned int BLOCK_9_SIZE>
-ConstraintSparse<RESIDUAL_SIZE,
-                 BLOCK_0_SIZE,
-                 BLOCK_1_SIZE,
-                 BLOCK_2_SIZE,
-                 BLOCK_3_SIZE,
-                 BLOCK_4_SIZE,
-                 BLOCK_5_SIZE,
-                 BLOCK_6_SIZE,
-                 BLOCK_7_SIZE,
-                 BLOCK_8_SIZE,
-                 BLOCK_9_SIZE>::ConstraintSparse(ConstraintType     _tp,
-                                                 bool               _apply_loss_function,
-                                                 ConstraintStatus   _status,
-                                                 StateBlockPtr _state0Ptr,
-                                                 StateBlockPtr _state1Ptr,
-                                                 StateBlockPtr _state2Ptr,
-                                                 StateBlockPtr _state3Ptr,
-                                                 StateBlockPtr _state4Ptr,
-                                                 StateBlockPtr _state5Ptr,
-                                                 StateBlockPtr _state6Ptr,
-                                                 StateBlockPtr _state7Ptr,
-                                                 StateBlockPtr _state8Ptr,
-                                                 StateBlockPtr _state9Ptr ) :
-            ConstraintBase(_tp, _apply_loss_function, _status),
-            state_ptr_vector_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr,_state9Ptr}),
-            state_block_sizes_vector_({BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,BLOCK_5_SIZE,BLOCK_6_SIZE,BLOCK_7_SIZE,BLOCK_8_SIZE,BLOCK_9_SIZE})
-        {
-            resizeVectors();
-        }
-
-template <const unsigned int RESIDUAL_SIZE,
-                unsigned int BLOCK_0_SIZE,
-                unsigned int BLOCK_1_SIZE,
-                unsigned int BLOCK_2_SIZE,
-                unsigned int BLOCK_3_SIZE,
-                unsigned int BLOCK_4_SIZE,
-                unsigned int BLOCK_5_SIZE,
-                unsigned int BLOCK_6_SIZE,
-                unsigned int BLOCK_7_SIZE,
-                unsigned int BLOCK_8_SIZE,
-                unsigned int BLOCK_9_SIZE>
-ConstraintSparse<RESIDUAL_SIZE,
-                 BLOCK_0_SIZE,
-                 BLOCK_1_SIZE,
-                 BLOCK_2_SIZE,
-                 BLOCK_3_SIZE,
-                 BLOCK_4_SIZE,
-                 BLOCK_5_SIZE,
-                 BLOCK_6_SIZE,
-                 BLOCK_7_SIZE,
-                 BLOCK_8_SIZE,
-                 BLOCK_9_SIZE>::ConstraintSparse(ConstraintType          _tp,
-                                                 const FrameBasePtr&     _frame_other_ptr,
-                                                 const FeatureBasePtr&   _feature_other_ptr,
-                                                 const LandmarkBasePtr&  _landmark_other_ptr,
-                                                 const ProcessorBasePtr& _processor_ptr,
-                                                 bool                    _apply_loss_function,
-                                                 ConstraintStatus        _status,
-                                                 StateBlockPtr _state0Ptr,
-                                                 StateBlockPtr _state1Ptr,
-                                                 StateBlockPtr _state2Ptr,
-                                                 StateBlockPtr _state3Ptr,
-                                                 StateBlockPtr _state4Ptr,
-                                                 StateBlockPtr _state5Ptr,
-                                                 StateBlockPtr _state6Ptr,
-                                                 StateBlockPtr _state7Ptr,
-                                                 StateBlockPtr _state8Ptr,
-                                                 StateBlockPtr _state9Ptr ) :
-            ConstraintBase(_tp, _frame_other_ptr, _feature_other_ptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status),
-            state_ptr_vector_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr,_state9Ptr}),
-            state_block_sizes_vector_({BLOCK_0_SIZE,BLOCK_1_SIZE,BLOCK_2_SIZE,BLOCK_3_SIZE,BLOCK_4_SIZE,BLOCK_5_SIZE,BLOCK_6_SIZE,BLOCK_7_SIZE,BLOCK_8_SIZE,BLOCK_9_SIZE})
-        {
-            resizeVectors();
-        }
-
-template <const unsigned int RESIDUAL_SIZE,
-                unsigned int BLOCK_0_SIZE,
-                unsigned int BLOCK_1_SIZE,
-                unsigned int BLOCK_2_SIZE,
-                unsigned int BLOCK_3_SIZE,
-                unsigned int BLOCK_4_SIZE,
-                unsigned int BLOCK_5_SIZE,
-                unsigned int BLOCK_6_SIZE,
-                unsigned int BLOCK_7_SIZE,
-                unsigned int BLOCK_8_SIZE,
-                unsigned int BLOCK_9_SIZE>
-const std::vector<Scalar*> ConstraintSparse<RESIDUAL_SIZE,
-                                                BLOCK_0_SIZE,
-                                                BLOCK_1_SIZE,
-                                                BLOCK_2_SIZE,
-                                                BLOCK_3_SIZE,
-                                                BLOCK_4_SIZE,
-                                                BLOCK_5_SIZE,
-                                                BLOCK_6_SIZE,
-                                                BLOCK_7_SIZE,
-                                                BLOCK_8_SIZE,
-                                                BLOCK_9_SIZE>::getStateScalarPtrVector()
-{
-    assert(state_ptr_vector_.size() > 0 && state_ptr_vector_.size() <= 10 && "Wrong state vector size in constraint, it should be between 1 and 10");
-
-    switch (state_ptr_vector_.size())
-    {
-        case 1:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr()});
-        }
-        case 2:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr()});
-        }
-        case 3:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr()});
-        }
-        case 4:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr()});
-        }
-        case 5:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr(),
-                                             state_ptr_vector_[4]->getPtr()});
-        }
-        case 6:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr(),
-                                             state_ptr_vector_[4]->getPtr(),
-                                             state_ptr_vector_[5]->getPtr()});
-        }
-        case 7:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr(),
-                                             state_ptr_vector_[4]->getPtr(),
-                                             state_ptr_vector_[5]->getPtr(),
-                                             state_ptr_vector_[6]->getPtr()});
-        }
-        case 8:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr(),
-                                             state_ptr_vector_[4]->getPtr(),
-                                             state_ptr_vector_[5]->getPtr(),
-                                             state_ptr_vector_[6]->getPtr(),
-                                             state_ptr_vector_[7]->getPtr()});
-        }
-        case 9:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr(),
-                                             state_ptr_vector_[4]->getPtr(),
-                                             state_ptr_vector_[5]->getPtr(),
-                                             state_ptr_vector_[6]->getPtr(),
-                                             state_ptr_vector_[7]->getPtr(),
-                                             state_ptr_vector_[8]->getPtr()});
-        }
-        case 10:
-        {
-            return std::vector<Scalar*>({state_ptr_vector_[0]->getPtr(),
-                                             state_ptr_vector_[1]->getPtr(),
-                                             state_ptr_vector_[2]->getPtr(),
-                                             state_ptr_vector_[3]->getPtr(),
-                                             state_ptr_vector_[4]->getPtr(),
-                                             state_ptr_vector_[5]->getPtr(),
-                                             state_ptr_vector_[6]->getPtr(),
-                                             state_ptr_vector_[7]->getPtr(),
-                                             state_ptr_vector_[8]->getPtr(),
-                                             state_ptr_vector_[9]->getPtr()});
-        }
-    }
-
-    return std::vector<Scalar*>(0); //Not going to happen
-}
-
-template <const unsigned int RESIDUAL_SIZE,
-                unsigned int BLOCK_0_SIZE,
-                unsigned int BLOCK_1_SIZE,
-                unsigned int BLOCK_2_SIZE,
-                unsigned int BLOCK_3_SIZE,
-                unsigned int BLOCK_4_SIZE,
-                unsigned int BLOCK_5_SIZE,
-                unsigned int BLOCK_6_SIZE,
-                unsigned int BLOCK_7_SIZE,
-                unsigned int BLOCK_8_SIZE,
-                unsigned int BLOCK_9_SIZE>
-const std::vector<StateBlockPtr> ConstraintSparse<RESIDUAL_SIZE,
-                                                BLOCK_0_SIZE,
-                                                BLOCK_1_SIZE,
-                                                BLOCK_2_SIZE,
-                                                BLOCK_3_SIZE,
-                                                BLOCK_4_SIZE,
-                                                BLOCK_5_SIZE,
-                                                BLOCK_6_SIZE,
-                                                BLOCK_7_SIZE,
-                                                BLOCK_8_SIZE,
-                                                BLOCK_9_SIZE>::getStateBlockPtrVector() const
-{
-    return state_ptr_vector_;
-}
-
-template <const unsigned int RESIDUAL_SIZE,
-                unsigned int BLOCK_0_SIZE,
-                unsigned int BLOCK_1_SIZE,
-                unsigned int BLOCK_2_SIZE,
-                unsigned int BLOCK_3_SIZE,
-                unsigned int BLOCK_4_SIZE,
-                unsigned int BLOCK_5_SIZE,
-                unsigned int BLOCK_6_SIZE,
-                unsigned int BLOCK_7_SIZE,
-                unsigned int BLOCK_8_SIZE,
-                unsigned int BLOCK_9_SIZE>
-unsigned int ConstraintSparse<RESIDUAL_SIZE,
-                              BLOCK_0_SIZE,
-                              BLOCK_1_SIZE,
-                              BLOCK_2_SIZE,
-                              BLOCK_3_SIZE,
-                              BLOCK_4_SIZE,
-                              BLOCK_5_SIZE,
-                              BLOCK_6_SIZE,
-                              BLOCK_7_SIZE,
-                              BLOCK_8_SIZE,
-                              BLOCK_9_SIZE>::getSize() const
-{
-    return RESIDUAL_SIZE;
-}
-
-
-template <const unsigned int RESIDUAL_SIZE,
-                unsigned int BLOCK_0_SIZE,
-                unsigned int BLOCK_1_SIZE,
-                unsigned int BLOCK_2_SIZE,
-                unsigned int BLOCK_3_SIZE,
-                unsigned int BLOCK_4_SIZE,
-                unsigned int BLOCK_5_SIZE,
-                unsigned int BLOCK_6_SIZE,
-                unsigned int BLOCK_7_SIZE,
-                unsigned int BLOCK_8_SIZE,
-                unsigned int BLOCK_9_SIZE>
-void ConstraintSparse<RESIDUAL_SIZE,
-                      BLOCK_0_SIZE,
-                      BLOCK_1_SIZE,
-                      BLOCK_2_SIZE,
-                      BLOCK_3_SIZE,
-                      BLOCK_4_SIZE,
-                      BLOCK_5_SIZE,
-                      BLOCK_6_SIZE,
-                      BLOCK_7_SIZE,
-                      BLOCK_8_SIZE,
-                      BLOCK_9_SIZE>::resizeVectors()
-{
-    for (unsigned int ii = 1; ii<state_block_sizes_vector_.size(); ii++)
-    {
-        if (state_block_sizes_vector_.at(ii) != 0)
-        {
-        	for (unsigned int jj = 0; jj < ii; jj++)
-        		assert(state_ptr_vector_.at(ii) != state_ptr_vector_.at(jj) && "ConstraintSparse: Repeated state block.");
-        	assert(state_ptr_vector_.at(ii) != nullptr && "ConstraintSparse: Null state pointer in a non-zero sized block!");
-        	assert(state_ptr_vector_[ii]->getSize() == state_block_sizes_vector_[ii] && "ConstraintSparse: Incoherent state block size and template block size");
-        }
-
-        else
-        {
-            assert(state_ptr_vector_.at(ii) == nullptr && "ConstraintSparse: Non-null state pointer in a zero sized block!");
-            state_ptr_vector_.resize(ii);
-            state_block_sizes_vector_.resize(ii);
-            break;
-        }
-    }
-}
-
-} // namespace wolf
-
-#endif
diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt
index c614b93723c22f70d73f529ca4f61ea392a748ff..b9a4b728a9554500b9a85ebe89d48651bce9470d 100644
--- a/src/examples/CMakeLists.txt
+++ b/src/examples/CMakeLists.txt
@@ -96,6 +96,10 @@ ENDIF(Suitesparse_FOUND)
 #ADD_EXECUTABLE(test_wolf_prunning test_wolf_prunning.cpp)
 #TARGET_LINK_LIBRARIES(test_wolf_prunning ${PROJECT_NAME})
 
+# Sparsification from wolf tree from .graph file (TORO)
+ADD_EXECUTABLE(test_sparsification test_sparsification.cpp)
+TARGET_LINK_LIBRARIES(test_sparsification ${PROJECT_NAME})
+
 # Comparing analytic and autodiff odometry constraints
 #ADD_EXECUTABLE(test_analytic_odom_constraint test_analytic_odom_constraint.cpp)
 #TARGET_LINK_LIBRARIES(test_analytic_odom_constraint ${PROJECT_NAME})
@@ -110,6 +114,11 @@ IF(OpenCV_FOUND)
         # Processor Image Landmark test
         ADD_EXECUTABLE(test_processor_image_landmark test_processor_image_landmark.cpp)
         TARGET_LINK_LIBRARIES(test_processor_image_landmark ${PROJECT_NAME})
+
+	    # Simple AHP test
+	    ADD_EXECUTABLE(test_simple_AHP test_simple_AHP.cpp)
+	    TARGET_LINK_LIBRARIES(test_simple_AHP ${PROJECT_NAME})
+
     ENDIF(Ceres_FOUND)
 
     # Testing opencv matching and fundamental matrix with ransac
@@ -131,15 +140,8 @@ IF(OpenCV_FOUND)
     # ORB tracker test
     ADD_EXECUTABLE(test_ROI_ORB test_ROI_ORB.cpp)
     TARGET_LINK_LIBRARIES(test_ROI_ORB ${PROJECT_NAME})
-ENDIF(OpenCV_FOUND)
 
-IF(Ceres_FOUND)
-    # Simple AHP test
-    IF(OpenCV_FOUND)
-      ADD_EXECUTABLE(test_simple_AHP test_simple_AHP.cpp)
-      TARGET_LINK_LIBRARIES(test_simple_AHP ${PROJECT_NAME})
-    ENDIF(OpenCV_FOUND)
-ENDIF(Ceres_FOUND)
+ENDIF(OpenCV_FOUND)
 
 # Processor Tracker Feature test
 ADD_EXECUTABLE(test_processor_tracker_feature test_processor_tracker_feature.cpp)
diff --git a/src/examples/test_ceres_2_lasers_polylines.cpp b/src/examples/test_ceres_2_lasers_polylines.cpp
index b2be568b0bd2fca63d110a178dbed35660e3d8f0..9c5f592ec5728d999f66cc688f73739d080eef86 100644
--- a/src/examples/test_ceres_2_lasers_polylines.cpp
+++ b/src/examples/test_ceres_2_lasers_polylines.cpp
@@ -328,8 +328,8 @@ int main(int argc, char** argv)
         // SOLVE OPTIMIZATION ---------------------------
         std::cout << "SOLVING..." << std::endl;
         t1 = clock();
-        ceres::Solver::Summary summary = ceres_manager.solve();
-        std::cout << summary.FullReport() << std::endl;
+        std::string summary = ceres_manager.solve(2);// 0: nothing, 1: BriefReport, 2: FullReport
+        std::cout << summary << std::endl;
         mean_times(3) += ((double) clock() - t1) / CLOCKS_PER_SEC;
 
         // COMPUTE COVARIANCES ---------------------------
diff --git a/src/examples/test_imuDock.cpp b/src/examples/test_imuDock.cpp
index 40c63e71b83a8550079c4f309c9c371fd94a7d9c..17d39a10c1d3544c5b317bab83827d41b2281837 100644
--- a/src/examples/test_imuDock.cpp
+++ b/src/examples/test_imuDock.cpp
@@ -240,7 +240,7 @@ int main(int argc, char** argv)
 
     // ___Solve + compute covariances___
     problem->print(4,0,1,0);
-    ceres::Solver::Summary summary = ceres_manager->solve();
+    std::string report = ceres_manager->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager->computeCovariances(ALL_MARGINALS);
     problem->print(1,0,1,0);
 
diff --git a/src/examples/test_imuDock_autoKFs.cpp b/src/examples/test_imuDock_autoKFs.cpp
index 1cbe8723eed660b93d3d27de9afb7ee053d04950..2f4b67fd8046e1950801ddd24bb10457e338ece6 100644
--- a/src/examples/test_imuDock_autoKFs.cpp
+++ b/src/examples/test_imuDock_autoKFs.cpp
@@ -249,7 +249,7 @@ int main(int argc, char** argv)
 
     // ___Solve + compute covariances___
     problem->print(4,0,1,0);
-    ceres::Solver::Summary summary = ceres_manager->solve();
+    std::string report = ceres_manager->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager->computeCovariances(ALL_MARGINALS);
     problem->print(1,0,1,0);
 
diff --git a/src/examples/test_imuPlateform_Offline.cpp b/src/examples/test_imuPlateform_Offline.cpp
index b77c82b6e6ccf49f6ce31788b1cc3a0bc52c0375..074e6ddb27c7ecc0223ca08352e51a9087e53a70 100644
--- a/src/examples/test_imuPlateform_Offline.cpp
+++ b/src/examples/test_imuPlateform_Offline.cpp
@@ -79,8 +79,7 @@ int main(int argc, char** argv)
     ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
     ceres_options.max_line_search_step_contraction = 1e-3;
     ceres_options.max_num_iterations = 1e4;
-    CeresManager* ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
-
+    CeresManager* ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
     // SENSOR + PROCESSOR IMU
     SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -202,8 +201,8 @@ int main(int argc, char** argv)
     origin_KF->getVPtr()->fix();
     
     std::cout << "\t\t\t ______solving______" << std::endl;
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
-    std::cout << summary.FullReport() << std::endl;
+    std::string report = ceres_manager_wolf_diff->solve(2);// 0: nothing, 1: BriefReport, 2: FullReport
+    std::cout << report << std::endl;
     ceres_manager_wolf_diff->computeCovariances(ALL);
     std::cout << "\t\t\t ______solved______" << std::endl;
 
diff --git a/src/examples/test_imu_constrained0.cpp b/src/examples/test_imu_constrained0.cpp
index 3e5e81c0f97df7c2160f4546b3e281c18b43b7d7..5869c6bfc71bc38ea645c22224e428d4067526a1 100644
--- a/src/examples/test_imu_constrained0.cpp
+++ b/src/examples/test_imu_constrained0.cpp
@@ -101,8 +101,7 @@ int main(int argc, char** argv)
     ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
     ceres_options.max_line_search_step_contraction = 1e-3;
     ceres_options.max_num_iterations = 1e4;
-    CeresManager* ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
-
+    CeresManager* ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
     // SENSOR + PROCESSOR IMU
     SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -194,7 +193,7 @@ int main(int argc, char** argv)
         if( (ts.get() - t.get()) >= 0.05 )
         {
             t = ts;
-            //ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+            //std::string report = ceres_manager_wolf_diff->solve(1); //0: nothing, 1: BriefReport, 2: FullReport
         
         
             Eigen::VectorXs frm_state(16);
@@ -260,15 +259,15 @@ int main(int argc, char** argv)
 
     
     std::cout << "\t\t\t ______solving______" << std::endl;
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
-    std::cout << summary.FullReport() << std::endl;
+    std::string report = ceres_manager_wolf_diff->solve(2); //0: nothing, 1: BriefReport, 2: FullReport
+    std::cout << report << std::endl;
 
     last_KF->getAccBiasPtr()->fix();
     last_KF->getGyroBiasPtr()->fix();
 
     std::cout << "\t\t\t solving after fixBias" << std::endl;
-    summary = ceres_manager_wolf_diff->solve();
-    std::cout << summary.BriefReport() << std::endl;
+    report = ceres_manager_wolf_diff->solve(1); //0: nothing, 1: BriefReport, 2: FullReport
+    std::cout << report << std::endl;
     ceres_manager_wolf_diff->computeCovariances(ALL);
     std::cout << "\t\t\t ______solved______" << std::endl;
 
diff --git a/src/examples/test_processor_image_landmark.cpp b/src/examples/test_processor_image_landmark.cpp
index 646160b61a84ca379f6bfb04778a3a760852e746..06495426a1de3b9ec4df946bf318589ce06902d4 100644
--- a/src/examples/test_processor_image_landmark.cpp
+++ b/src/examples/test_processor_image_landmark.cpp
@@ -264,8 +264,8 @@ int main(int argc, char** argv)
         if (problem->getTrajectoryPtr()->getFrameList().size() > number_of_KFs)
         {
             number_of_KFs = problem->getTrajectoryPtr()->getFrameList().size();
-            ceres::Solver::Summary summary = ceres_manager.solve();
-            std::cout << summary.BriefReport() << std::endl;
+            std::string summary = ceres_manager.solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
+            std::cout << summary << std::endl;
         }
 
 
diff --git a/src/examples/test_processor_odom_3D.cpp b/src/examples/test_processor_odom_3D.cpp
index 9e17469d10b5465431bebad5a2b5989d57b3c88d..c43b1f50807d259e8f8a13da6ea8a9701a7771b9 100644
--- a/src/examples/test_processor_odom_3D.cpp
+++ b/src/examples/test_processor_odom_3D.cpp
@@ -89,9 +89,8 @@ int main (int argc, char** argv)
 //        frm->setState(problem->zeroState());
 //    }
 //    problem->print(1,0,1,0);
-    ceres::Solver::Summary summary = ceres_manager.solve();
-    std::cout << summary.BriefReport() << std::endl;
-    summary.FullReport();
+    std::string brief_report = ceres_manager.solve(1);// 0, 1 or 2
+    std::cout << brief_report << std::endl;
     problem->print(1,0,1,0);
 
     problem.reset();
diff --git a/src/examples/test_simple_AHP.cpp b/src/examples/test_simple_AHP.cpp
index 052b528865d927611356ae38b80f682f48ffdbc5..d31eba5ab0db4735847ec354b13dcb6ddb206812 100644
--- a/src/examples/test_simple_AHP.cpp
+++ b/src/examples/test_simple_AHP.cpp
@@ -244,8 +244,8 @@ int main(int argc, char** argv)
     CeresManager ceres_manager(problem, ceres_options);
 
 
-    ceres::Solver::Summary summary = ceres_manager.solve();
-    std::cout << summary.FullReport() << std::endl;
+    std::string summary = ceres_manager.solve(2);// 0: nothing, 1: BriefReport, 2: FullReport
+    std::cout << summary << std::endl;
 
     // Test of convergence over the lmk params
     bool pass = (lmk_2->point() - lmk_1->point()).isMuchSmallerThan(1,Constants::EPS);
diff --git a/src/examples/test_sparsification.cpp b/src/examples/test_sparsification.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bf797869098964ffe95683a7155e8657d6622b4f
--- /dev/null
+++ b/src/examples/test_sparsification.cpp
@@ -0,0 +1,315 @@
+// Sparsification example creating wolf tree from imported graph from .txt file
+
+//C includes for sleep, time and main args
+#include "unistd.h"
+
+//std includes
+#include <cstdlib>
+#include <fstream>
+#include <string>
+#include <iostream>
+#include <memory>
+#include <random>
+#include <cmath>
+#include <queue>
+
+//Wolf includes
+#include "capture_void.h"
+#include "feature_odom_2D.h"
+#include "constraint_base.h"
+#include "ceres_wrapper/ceres_manager.h"
+
+// EIGEN
+//#include <Eigen/CholmodSupport>
+#include <Eigen/StdVector> // Eigen in std vector
+
+namespace wolf{
+// inserts the sparse matrix 'ins' into the sparse matrix 'original' in the place given by 'row' and 'col' integers
+
+void insertSparseBlock(const Eigen::SparseMatrix<Scalar>& ins, Eigen::SparseMatrix<Scalar>& original, const unsigned int& row, const unsigned int& col)
+{
+  for (int k=0; k<ins.outerSize(); ++k)
+    for (Eigen::SparseMatrix<Scalar>::InnerIterator iti(ins,k); iti; ++iti)
+      original.coeffRef(iti.row() + row, iti.col() + col) = iti.value();
+
+  original.makeCompressed();
+}
+
+void decodeEdge(const std::string& buffer, unsigned int& edge_from, unsigned int& edge_to, Eigen::Vector3s& measurement, Eigen::Matrix3s& covariance)
+{
+	std::string str_num;
+
+	unsigned int i = 0;
+
+	// only decode edges
+	if (buffer.at(0) == 'E')
+	{
+		//skip rest of EDGE word
+		while (buffer.at(i) != ' ') i++;
+		//skip white spaces
+		while (buffer.at(i) == ' ') i++;
+
+		// FROM ID
+		while (buffer.at(i) != ' ')
+			str_num.push_back(buffer.at(i++));
+		edge_from = atoi(str_num.c_str())+1;
+		str_num.clear();
+
+		//skip white spaces
+		while (buffer.at(i) == ' ') i++;
+
+		// TO ID
+		while (buffer.at(i) != ' ')
+			str_num.push_back(buffer.at(i++));
+		edge_to = atoi(str_num.c_str())+1;
+		str_num.clear();
+
+		//skip white spaces
+		while (buffer.at(i) == ' ') i++;
+
+		// MEASUREMENT
+		// X
+		while (buffer.at(i) != ' ')
+			str_num.push_back(buffer.at(i++));
+		measurement(0) = atof(str_num.c_str());
+		str_num.clear();
+		//skip white spaces
+		while (buffer.at(i) == ' ') i++;
+		// Y
+		while (buffer.at(i) != ' ')
+			str_num.push_back(buffer.at(i++));
+		measurement(1) = atof(str_num.c_str());
+		str_num.clear();
+		//skip white spaces
+		while (buffer.at(i) == ' ') i++;
+		// THETA
+		while (buffer.at(i) != ' ')
+			str_num.push_back(buffer.at(i++));
+		measurement(2) = atof(str_num.c_str());
+		str_num.clear();
+		//skip white spaces
+		while (buffer.at(i) == ' ') i++;
+
+		// INFORMATION
+		Eigen::Matrix3s information;
+		// XX
+		while (buffer.at(i) != ' ')
+			str_num.push_back(buffer.at(i++));
+		information(0,0) = atof(str_num.c_str());
+		str_num.clear();
+		//skip white spaces
+		while (buffer.at(i) == ' ') i++;
+		// XY
+		while (buffer.at(i) != ' ')
+			str_num.push_back(buffer.at(i++));
+		information(0,1) = atof(str_num.c_str());
+		information(1,0) = atof(str_num.c_str());
+		str_num.clear();
+		//skip white spaces
+		while (buffer.at(i) == ' ') i++;
+		// YY
+		while (buffer.at(i) != ' ')
+			str_num.push_back(buffer.at(i++));
+		information(1,1) = atof(str_num.c_str());
+		str_num.clear();
+		//skip white spaces
+		while (buffer.at(i) == ' ') i++;
+		// THETATHETA
+		while (buffer.at(i) != ' ')
+			str_num.push_back(buffer.at(i++));
+		information(2,2) = atof(str_num.c_str());
+		str_num.clear();
+		//skip white spaces
+		while (buffer.at(i) == ' ') i++;
+		// XTHETA
+		while (buffer.at(i) != ' ')
+			str_num.push_back(buffer.at(i++));
+		information(0,2) = atof(str_num.c_str());
+		information(2,0) = atof(str_num.c_str());
+		str_num.clear();
+		//skip white spaces
+		while (buffer.at(i) == ' ') i++;
+		// YTHETA
+		while (i < buffer.size() && buffer.at(i) != ' ')
+			str_num.push_back(buffer.at(i++));
+		information(1,2) = atof(str_num.c_str());
+		information(2,1) = atof(str_num.c_str());
+		str_num.clear();
+
+		// COVARIANCE
+		covariance = information.inverse();
+	}
+	else
+	{
+		edge_from = 0;
+		edge_to   = 0;
+	}
+}
+
+}
+
+int main(int argc, char** argv) 
+{
+    using namespace wolf;
+
+    //Welcome message
+    std::cout << std::endl << " ========= WOLF IMPORTED .graph TEST ===========" << std::endl << std::endl;
+
+    bool wrong_input = false;
+    if (argc < 3)
+    	wrong_input = true;
+    else if (argc > 4)
+    	wrong_input = true;
+    else if (argc > 2 && (atoi(argv[2]) < 2 || atoi(argv[2]) > 5))
+    	wrong_input = true;
+    else if (argc > 3 && atoi(argv[3]) < 0 )
+    	wrong_input = true;
+
+    if (wrong_input)
+    {
+        std::cout << "Please call me with: [./test_wolf_imported_graph DATASET T (MAX_VERTICES)], where:" << std::endl;
+        std::cout << "    DATASET: manhattan, killian or intel" << std::endl;
+        std::cout << "    T keep one node each T: 2, 3, 4 or 5" << std::endl;
+        std::cout << "    optional: MAX_VERTICES max edges to be loaded" << std::endl;
+        std::cout << "EXIT due to bad user input" << std::endl << std::endl;
+        return -1;
+    }
+
+    // input variables
+    char const * dataset_path = std::getenv("DATASET_PATH");
+	unsigned int pruning_T = atoi(argv[2]);
+    std::string file_path(dataset_path);
+	file_path = file_path + "/graphs/redirected_" + std::to_string(pruning_T) + "_" + argv[1] + ".graph";
+	unsigned int MAX_VERTEX = 1e9;
+	if (argc > 3 && atoi(argv[3]) != 0)
+    	MAX_VERTEX = atoi(argv[3]);
+
+    // Wolf problem
+    FrameBasePtr last_frame_ptr, frame_from_ptr, frame_to_ptr;
+    ProblemPtr bl_problem_ptr = Problem::create("PO_2D");
+    SensorBasePtr sensor_ptr = bl_problem_ptr->installSensor("ODOM 2D", "Odometry", Eigen::VectorXs::Zero(3), IntrinsicsBasePtr());
+
+    // Ceres wrapper
+    std::string bl_summary, sp_summary;
+    ceres::Solver::Options ceres_options;
+    ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;LINE_SEARCH
+    ceres_options.max_line_search_step_contraction = 1e-3;
+    ceres_options.max_num_iterations = 10;
+    CeresManagerPtr bl_ceres_manager = std::make_shared<CeresManager>(bl_problem_ptr, ceres_options);
+
+    // load graph from .txt
+    std::ifstream graph_file;
+    graph_file.open(file_path.c_str(), std::ifstream::in);
+    if (!graph_file.is_open())
+    {
+    	printf("\nError opening file: %s\n",file_path.c_str());
+    	return -1;
+    }
+
+    // auxiliar variables
+	std::string line_string;
+	unsigned int edge_from, edge_to;
+	Eigen::Vector3s meas;
+	Eigen::Matrix3s meas_cov;
+	Eigen::Matrix3s R = Eigen::Matrix3s::Identity();
+	//clock_t t1;
+
+	// ------------------------ START EXPERIMENT ------------------------
+	// First frame FIXED
+	last_frame_ptr = bl_problem_ptr->emplaceFrame(KEY_FRAME, Eigen::Vector3s::Zero(),TimeStamp(0));
+	last_frame_ptr->fix();
+	bl_problem_ptr->print(4, true, false, true);
+
+	while (std::getline(graph_file, line_string) && last_frame_ptr->id() <= MAX_VERTEX)
+	{
+		std::cout << "new line:" << line_string << std::endl;
+		decodeEdge(line_string, edge_from, edge_to, meas, meas_cov);
+
+		// only factors
+		if (edge_from != 0)
+		{
+
+			// ODOMETRY -------------------
+			if (edge_to > last_frame_ptr->id())
+			{
+				frame_from_ptr = last_frame_ptr;
+
+				// NEW KEYFRAME
+				Eigen::Vector3s from_pose = frame_from_ptr->getState();
+				R.topLeftCorner(2,2) = Eigen::Rotation2Ds(from_pose(2)).matrix();
+				Eigen::Vector3s new_frame_pose = from_pose + R*meas;
+				last_frame_ptr = bl_problem_ptr->emplaceFrame(KEY_FRAME, new_frame_pose, TimeStamp(double(edge_to)));
+
+				frame_to_ptr = last_frame_ptr;
+
+				std::cout << "NEW FRAME " << last_frame_ptr->id() << " - ts = " << last_frame_ptr->getTimeStamp().get() << std::endl;
+
+				// REMOVE PREVIOUS NODES
+			}
+			// LOOP CLOSURE ---------------
+			else
+			{
+				if (edge_from == last_frame_ptr->id())
+					frame_from_ptr = last_frame_ptr;
+				else
+					for (auto frm_rit = bl_problem_ptr->getTrajectoryPtr()->getFrameList().rbegin(); frm_rit != bl_problem_ptr->getTrajectoryPtr()->getFrameList().rend(); frm_rit++)
+						if ((*frm_rit)->id() == edge_from)
+						{
+							frame_from_ptr = *frm_rit;
+							break;
+						}
+				if (edge_to == last_frame_ptr->id())
+					frame_to_ptr = last_frame_ptr;
+				else
+					for (auto frm_rit = bl_problem_ptr->getTrajectoryPtr()->getFrameList().rbegin(); frm_rit != bl_problem_ptr->getTrajectoryPtr()->getFrameList().rend(); frm_rit++)
+						if ((*frm_rit)->id() == edge_to)
+						{
+							frame_to_ptr = *frm_rit;
+							break;
+						}
+			}
+//			std::cout << "frame_from " << frame_from_ptr->id() << std::endl;
+//			std::cout << "edge_from " << edge_from << std::endl;
+//			std::cout << "frame_to " << frame_to_ptr->id() << std::endl;
+//			std::cout << "edge_to " << edge_to << std::endl;
+
+			assert(frame_from_ptr->id() == edge_from && "frame from id and edge from idx must be the same");
+			assert(frame_to_ptr->id() == edge_to && "frame to id and edge to idx must be the same");
+
+			// CAPTURE
+			CaptureVoidPtr capture_ptr = std::make_shared<CaptureVoid>(TimeStamp(0), sensor_ptr);
+			frame_from_ptr->addCapture(capture_ptr);
+
+			// FEATURE
+			FeatureBasePtr feature_ptr = std::make_shared<FeatureOdom2D>(meas, meas_cov);
+			capture_ptr->addFeature(feature_ptr);
+
+			// CONSTRAINT
+			ConstraintOdom2DPtr constraint_ptr = std::make_shared<ConstraintOdom2D>(feature_ptr, frame_to_ptr);
+			feature_ptr->addConstraint(constraint_ptr);
+			frame_to_ptr->addConstrainedBy(constraint_ptr);
+
+			// SOLVE
+			// solution
+			bl_summary = bl_ceres_manager->solve(1);
+		    std::cout << bl_summary << std::endl;
+
+			// covariance
+		    bl_ceres_manager->computeCovariances(ALL);//ALL_MARGINALS
+
+
+	//		t1 = clock();
+	//		double t_sigma_manual = 0;
+	//		t_sigma_manual += ((double) clock() - t1) / CLOCKS_PER_SEC;
+
+		}
+	}
+
+	//bl_problem_ptr->print(4, true, false, true);
+
+    //End message
+    std::cout << " =========================== END ===============================" << std::endl << std::endl;
+       
+    //exit
+    return 0;
+}
diff --git a/src/feature_base.cpp b/src/feature_base.cpp
index f5dd0d1e444b36078c6f144caca526382aa0dd42..13b9987f5c8adcdb8add385aae6c3e10c584707f 100644
--- a/src/feature_base.cpp
+++ b/src/feature_base.cpp
@@ -13,11 +13,9 @@ FeatureBase::FeatureBase(const std::string& _type, const Eigen::VectorXs& _measu
     feature_id_(++feature_id_count_),
     track_id_(0),
     landmark_id_(0),
-	measurement_(_measurement),
-	measurement_covariance_(_meas_covariance)
+	measurement_(_measurement)
 {
-    measurement_sqrt_information_upper_ = computeSqrtInformationUpper(measurement_covariance_);
-
+    setMeasurementCovariance(_meas_covariance);
 //    std::cout << "constructed      +f" << id() << std::endl;
 }
 
@@ -84,10 +82,18 @@ void FeatureBase::setMeasurementCovariance(const Eigen::MatrixXs & _meas_cov)
     assert(_meas_cov.determinant() > 0 && "Not positive definite measurement covariance");
 
     measurement_covariance_ = _meas_cov;
-	measurement_sqrt_information_upper_ = computeSqrtInformationUpper(_meas_cov);
+	measurement_sqrt_information_upper_ = computeSqrtUpper(_meas_cov);
+}
+
+void FeatureBase::setMeasurementInfo(const Eigen::MatrixXs & _meas_info)
+{
+    assert(_meas_info.determinant() > 0 && "Not positive definite measurement information");
+
+    measurement_covariance_ = _meas_info.inverse();
+    measurement_sqrt_information_upper_ = computeSqrtUpper(_meas_info.inverse());
 }
 
-Eigen::MatrixXs FeatureBase::computeSqrtInformationUpper(const Eigen::MatrixXs & _covariance) const
+Eigen::MatrixXs FeatureBase::computeSqrtUpper(const Eigen::MatrixXs & _covariance) const
 {
     if (_covariance.determinant() < Constants::EPS_SMALL)
     {
diff --git a/src/feature_base.h b/src/feature_base.h
index 2b92f537e9053e0bf4b635b03dd5533b4736323a..2e700eab9dac0c55aaf4b4c76010f507e8eedcba 100644
--- a/src/feature_base.h
+++ b/src/feature_base.h
@@ -64,6 +64,7 @@ class FeatureBase : public NodeBase, public std::enable_shared_from_this<Feature
         const Eigen::VectorXs& getMeasurement() const;
         void setMeasurement(const Eigen::VectorXs& _meas);
         void setMeasurementCovariance(const Eigen::MatrixXs & _meas_cov);
+        void setMeasurementInfo(const Eigen::MatrixXs & _meas_info);
         const Eigen::MatrixXs& getMeasurementCovariance() const;
         const Eigen::MatrixXs& getMeasurementSquareRootInformationUpper() const;
 
@@ -89,7 +90,7 @@ class FeatureBase : public NodeBase, public std::enable_shared_from_this<Feature
         void getConstraintList(ConstraintBaseList & _ctr_list);
 
     private:
-        Eigen::MatrixXs computeSqrtInformationUpper(const Eigen::MatrixXs& covariance) const;
+        Eigen::MatrixXs computeSqrtUpper(const Eigen::MatrixXs& _M) const;
 
 };
 
diff --git a/src/frame_base.cpp b/src/frame_base.cpp
index 0ba15c7449ca2dcf48900c5f3cf5537aae3906b8..50f6e8bbf0f71afe99e0a7e38f71a9fca4ea246f 100644
--- a/src/frame_base.cpp
+++ b/src/frame_base.cpp
@@ -182,6 +182,15 @@ void FrameBase::getState(Eigen::VectorXs& state) const
         }
 }
 
+unsigned int FrameBase::getSize() const
+{
+    unsigned int size = 0;
+    for (auto st : state_block_vec_)
+        if (st)
+            size += st->getSize();
+    return size;
+}
+
 FrameBasePtr FrameBase::getPreviousFrame() const
 {
     //std::cout << "finding previous frame of " << this->frame_id_ << std::endl;
diff --git a/src/frame_base.h b/src/frame_base.h
index 4ffb5aa03f868ecd5adf06c348690748353d2dfe..408b6b0bc9f061fd3e6bb703bd829a88f80bef09 100644
--- a/src/frame_base.h
+++ b/src/frame_base.h
@@ -118,7 +118,7 @@ class FrameBase : public NodeBase, public std::enable_shared_from_this<FrameBase
         void setState(const Eigen::VectorXs& _st);
         Eigen::VectorXs getState() const;
         void getState(Eigen::VectorXs& state) const;
-
+        unsigned int getSize() const;
 
         // Wolf tree access ---------------------------------------------------
     public:
diff --git a/src/problem.cpp b/src/problem.cpp
index c9eeb21c041a8643f97808a45a316a88f4661873..080e392fe4647a0f608ba8b002ff5a932402f041 100644
--- a/src/problem.cpp
+++ b/src/problem.cpp
@@ -359,72 +359,70 @@ void Problem::addLandmarkList(LandmarkBaseList& _lmk_list)
 
 StateBlockPtr Problem::addStateBlock(StateBlockPtr _state_ptr)
 {
-    //std::cout << "addStateBlockPtr" << std::endl;
+    //std::cout << "Problem::addStateBlockPtr " << _state_ptr.get() << std::endl;
+
     // add the state unit to the list
     state_block_list_.push_back(_state_ptr);
     // queue for solver manager
     state_block_notification_list_.push_back(StateBlockNotification({ADD,_state_ptr}));
-
     return _state_ptr;
 }
 
 void Problem::updateStateBlockPtr(StateBlockPtr _state_ptr)
 {
+    //std::cout << "Problem::updateStateBlockPtr " << _state_ptr.get() << std::endl;
+
     // queue for solver manager
     state_block_notification_list_.push_back(StateBlockNotification({UPDATE,_state_ptr}));
 }
 
 void Problem::removeStateBlockPtr(StateBlockPtr _state_ptr)
 {
+    //std::cout << "Problem::removeStateBlockPtr " << _state_ptr.get() << std::endl;
+
     // add the state unit to the list
     state_block_list_.remove(_state_ptr);
 
     // Check if the state addition is still as a notification
-    auto state_found_it = state_block_notification_list_.end();
-    for (auto state_notif_it = state_block_notification_list_.begin(); state_notif_it != state_block_notification_list_.end(); state_notif_it++)
-    {
+    auto state_notif_it = state_block_notification_list_.begin();
+    for (; state_notif_it != state_block_notification_list_.end(); state_notif_it++)
         if (state_notif_it->notification_ == ADD && state_notif_it->state_block_ptr_ == _state_ptr)
-        {
-            state_found_it = state_notif_it;
             break;
-        }
-    }
+
     // Remove addition notification
-    if (state_found_it != state_block_notification_list_.end())
-    	state_block_notification_list_.erase(state_found_it);
+    if (state_notif_it != state_block_notification_list_.end())
+    	state_block_notification_list_.erase(state_notif_it);
     // Add remove notification
     else
-    	state_block_notification_list_.push_back(StateBlockNotification({REMOVE, nullptr, _state_ptr->getPtr()}));
+    	state_block_notification_list_.push_back(StateBlockNotification({REMOVE, _state_ptr}));
 
 }
 
 ConstraintBasePtr Problem::addConstraintPtr(ConstraintBasePtr _constraint_ptr)
 {
-    //std::cout << "addConstraintPtr" << std::endl;
+    //std::cout << "Problem::addConstraintPtr " << _constraint_ptr->id() << std::endl;
     // queue for solver manager
-    constraint_notification_list_.push_back(ConstraintNotification({ADD, _constraint_ptr, _constraint_ptr->id()}));
+    constraint_notification_list_.push_back(ConstraintNotification({ADD, _constraint_ptr}));
 
     return _constraint_ptr;
 }
 
 void Problem::removeConstraintPtr(ConstraintBasePtr _constraint_ptr)
 {
+    //std::cout << "Problem::removeConstraintPtr " << _constraint_ptr->id() << std::endl;
+
     // Check if the constraint addition is still as a notification
-    auto ctr_found_it = constraint_notification_list_.end();
-    for (auto ctr_notif_it = constraint_notification_list_.begin(); ctr_notif_it != constraint_notification_list_.end(); ctr_notif_it++)
-    {
+    auto ctr_notif_it = constraint_notification_list_.begin();
+    for (; ctr_notif_it != constraint_notification_list_.end(); ctr_notif_it++)
         if (ctr_notif_it->notification_ == ADD && ctr_notif_it->constraint_ptr_ == _constraint_ptr)
-        {
-            ctr_found_it = ctr_notif_it;
             break;
-        }
-    }
+
     // Remove addition notification
-    if (ctr_found_it != constraint_notification_list_.end())
-        constraint_notification_list_.erase(ctr_found_it);
+    if (ctr_notif_it != constraint_notification_list_.end())
+        constraint_notification_list_.erase(ctr_notif_it); // CHECKED shared_ptr is not active after erase
     // Add remove notification
     else
-        constraint_notification_list_.push_back(ConstraintNotification({REMOVE, nullptr, _constraint_ptr->id()}));
+        constraint_notification_list_.push_back(ConstraintNotification({REMOVE, _constraint_ptr}));
 }
 
 void Problem::clearCovariance()
@@ -468,6 +466,45 @@ bool Problem::getCovarianceBlock(StateBlockPtr _state1, StateBlockPtr _state2, E
     return true;
 }
 
+bool Problem::getCovarianceBlock(std::map<StateBlockPtr, unsigned int> _sb_2_idx, Eigen::MatrixXs& _cov)
+{
+    // fill covariance
+    for (auto it1 = _sb_2_idx.begin(); it1 != _sb_2_idx.end(); it1++)
+        for (auto it2 = it1; it2 != _sb_2_idx.end(); it2++)
+        {
+            StateBlockPtr sb1 = it1->first;
+            StateBlockPtr sb2 = it2->first;
+            std::pair<StateBlockPtr, StateBlockPtr> pair_12(sb1, sb2);
+            std::pair<StateBlockPtr, StateBlockPtr> pair_21(sb2, sb1);
+
+            // search st1 & st2
+            if (covariances_.find(pair_12) != covariances_.end())
+            {
+                assert(_sb_2_idx[sb1] + sb1->getSize() <= _cov.rows() &&
+                       _sb_2_idx[sb2] + sb2->getSize() <= _cov.cols() && "Problem::getCovarianceBlock: Bad matrix covariance size!");
+                assert(_sb_2_idx[sb2] + sb2->getSize() <= _cov.rows() &&
+                       _sb_2_idx[sb1] + sb1->getSize() <= _cov.cols() && "Problem::getCovarianceBlock: Bad matrix covariance size!");
+
+                _cov.block(_sb_2_idx[sb1], _sb_2_idx[sb2], sb1->getSize(), sb2->getSize()) = covariances_[pair_12];
+                _cov.block(_sb_2_idx[sb2], _sb_2_idx[sb1], sb2->getSize(), sb1->getSize()) = covariances_[pair_12].transpose();
+            }
+            else if (covariances_.find(pair_21) != covariances_.end())
+            {
+                assert(_sb_2_idx[sb1] + sb1->getSize() <= _cov.rows() &&
+                       _sb_2_idx[sb2] + sb2->getSize() <= _cov.cols() && "Problem::getCovarianceBlock: Bad matrix covariance size!");
+                assert(_sb_2_idx[sb2] + sb2->getSize() <= _cov.rows() &&
+                       _sb_2_idx[sb1] + sb1->getSize() <= _cov.cols() && "Problem::getCovarianceBlock: Bad matrix covariance size!");
+
+                _cov.block(_sb_2_idx[sb1], _sb_2_idx[sb2], sb1->getSize(), sb2->getSize()) = covariances_[pair_21].transpose();
+                _cov.block(_sb_2_idx[sb2], _sb_2_idx[sb1], sb2->getSize(), sb1->getSize()) = covariances_[pair_21];
+            }
+            else
+                return false;
+        }
+
+    return true;
+}
+
 bool Problem::getCovarianceBlock(StateBlockPtr _state, Eigen::MatrixXs& _cov, const int _row_and_col)
 {
     return getCovarianceBlock(_state, _state, _cov, _row_and_col, _row_and_col);
diff --git a/src/problem.h b/src/problem.h
index d4f10e6474d230668cc50ea0c774699f3af9bc0c..48b68ed6452ab76ec739dc834a922472fb55d069 100644
--- a/src/problem.h
+++ b/src/problem.h
@@ -30,15 +30,13 @@ enum Notification
 };
 struct StateBlockNotification
 {
-        Notification notification_;
-        StateBlockPtr state_block_ptr_;
-        Scalar* scalar_ptr_;
+    Notification notification_;
+    StateBlockPtr state_block_ptr_;
 };
 struct ConstraintNotification
 {
-        Notification notification_;
-        ConstraintBasePtr constraint_ptr_; // TODO check pointer type
-        unsigned int id_;
+    Notification notification_;
+    ConstraintBasePtr constraint_ptr_;
 };
 
 
@@ -245,8 +243,8 @@ class Problem : public std::enable_shared_from_this<Problem>
         // Covariances -------------------------------------------
         void clearCovariance();
         void addCovarianceBlock(StateBlockPtr _state1, StateBlockPtr _state2, const Eigen::MatrixXs& _cov);
-        bool getCovarianceBlock(StateBlockPtr _state1, StateBlockPtr _state2, Eigen::MatrixXs& _cov, const int _row = 0,
-                                const int _col=0);
+        bool getCovarianceBlock(StateBlockPtr _state1, StateBlockPtr _state2, Eigen::MatrixXs& _cov, const int _row = 0, const int _col=0);
+        bool getCovarianceBlock(std::map<StateBlockPtr, unsigned int> _sb_2_idx, Eigen::MatrixXs& _cov);
         bool getCovarianceBlock(StateBlockPtr _state, Eigen::MatrixXs& _cov, const int _row_and_col = 0);
         bool getFrameCovariance(FrameBasePtr _frame_ptr, Eigen::MatrixXs& _covariance);
         Eigen::MatrixXs getFrameCovariance(FrameBasePtr _frame_ptr);
@@ -254,7 +252,6 @@ class Problem : public std::enable_shared_from_this<Problem>
         bool getLandmarkCovariance(LandmarkBasePtr _landmark_ptr, Eigen::MatrixXs& _covariance);
         Eigen::MatrixXs getLandmarkCovariance(LandmarkBasePtr _landmark_ptr);
 
-
         // Solver management ----------------------------------------
 
         /** \brief Gets a reference to the state units list
diff --git a/src/solver/sparse_utils.h b/src/solver/sparse_utils.h
index 04dd88db8afd910841c90c93a5485fd2ef5a4e4d..280aa2310c648ca360a491de6be6784826404f8a 100644
--- a/src/solver/sparse_utils.h
+++ b/src/solver/sparse_utils.h
@@ -5,45 +5,42 @@
  *      Author: jvallve
  */
 
-#ifndef TRUNK_SRC_SOLVER_SPARSE_UTILS_H_
-#define TRUNK_SRC_SOLVER_SPARSE_UTILS_H_
+#ifndef SPARSE_UTILS_H_
+#define SPARSE_UTILS_H_
 
 // eigen includes
 #include <eigen3/Eigen/Sparse>
 
-class SparseBlockPruning
+namespace wolf
 {
-    public:
-        unsigned int col, row, Nrows, Ncols;
-        SparseBlockPruning(unsigned int _col, unsigned int _row, unsigned int _Nrows, unsigned int _Ncols) :
-                col(_col),
-                row(_row),
-                Nrows(_Nrows),
-                Ncols(_Ncols)
-        {
-            //
-        }
-        bool operator()(unsigned int i, unsigned int j, double) const
-        {
-            return (i < row || i > row + Nrows-1) || (j < col || j > col + Ncols-1);
-        }
-};
-
-void eraseSparseBlock(Eigen::SparseMatrix<double>& original, const unsigned int& row, const unsigned int& col, const unsigned int& Nrows, const unsigned int& Ncols)
+
+void eraseBlockRow(Eigen::SparseMatrixs& A, const unsigned int& _row, const unsigned int& _n_rows)
 {
-    // prune all non-zero elements that not satisfy the 'keep' operand
-    // elements that are not in the block rows or are not in the block columns should be kept
+    A.prune([](int i, int, Scalar) { return i >= _row && i < _row + _n_rows; });
+}
 
-    SparseBlockPruning bp(row, col, Nrows, Ncols);
-    original.prune(bp);
+void eraseBlockCol(Eigen::SparseMatrixs& A, const unsigned int& _col, const unsigned int& _n_cols)
+{
+    A.prune([](int, int j, Scalar) { return j >= _col && j < _col + _n_cols; });
 }
 
-void addSparseBlock(const Eigen::MatrixXd& ins, Eigen::SparseMatrix<double>& original, const unsigned int& row, const unsigned int& col)
+void addSparseBlock(const Eigen::MatrixXs& ins, Eigen::SparseMatrixs& original, const unsigned int& row, const unsigned int& col)
 {
-  for (unsigned int r=0; r<ins.rows(); ++r)
-      for (unsigned int c = 0; c < ins.cols(); c++)
-          if (ins(r,c) != 0)
-              original.coeffRef(r + row, c + col) += ins(r,c);
+    for (auto ins_row = 0; ins_row < ins.rows(); ins_row++)
+        for (auto ins_col = 0; ins_col < ins.cols(); ins_col++)
+            original.coeffRef(row+ins_row, col+ins_col) += ins(ins_row,ins_col);
+
+    original.makeCompressed();
 }
 
-#endif /* TRUNK_SRC_SOLVER_SPARSE_UTILS_H_ */
+void insertSparseBlock(const Eigen::MatrixXs& ins, Eigen::SparseMatrixs& original, const unsigned int& row, const unsigned int& col)
+{
+    for (auto ins_row = 0; ins_row < ins.rows(); ins_row++)
+        for (auto ins_col = 0; ins_col < ins.cols(); ins_col++)
+            original.insert(row+ins_row, col+ins_col) = ins(ins_row,ins_col);
+
+    original.makeCompressed();
+}
+
+}
+#endif /* SPARSE_UTILS_H_ */
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
index 9f5f51f7a02255d99fc87b944f933a43a268b784..3763631a09f9297e2c7758383fe92d93ef9aaf33 100644
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -45,8 +45,8 @@ wolf_add_gtest(gtest_capture_base gtest_capture_base.cpp)
 target_link_libraries(gtest_capture_base ${PROJECT_NAME})
 
 # CaptureBase class test
-wolf_add_gtest(gtest_constraint_sparse gtest_constraint_sparse.cpp)
-target_link_libraries(gtest_constraint_sparse ${PROJECT_NAME})
+#wolf_add_gtest(gtest_constraint_sparse gtest_constraint_sparse.cpp)
+#target_link_libraries(gtest_constraint_sparse ${PROJECT_NAME})
 
 # FeatureBase classes test
 wolf_add_gtest(gtest_feature_base gtest_feature_base.cpp)
@@ -134,6 +134,10 @@ target_link_libraries(gtest_odom_2D ${PROJECT_NAME})
 wolf_add_gtest(gtest_odom_3D gtest_odom_3D.cpp)
 target_link_libraries(gtest_odom_3D ${PROJECT_NAME})
 
+# ConstraintAutodiff class test
+wolf_add_gtest(gtest_constraint_autodiff gtest_constraint_autodiff.cpp)
+target_link_libraries(gtest_constraint_autodiff ${PROJECT_NAME})
+
 # ROI test
 IF(OpenCV_FOUND)
   # Problem class test
diff --git a/src/test/gtest_constraint_autodiff.cpp b/src/test/gtest_constraint_autodiff.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..52b5d1c121987779fb20661319f5b8f1a27fd8ad
--- /dev/null
+++ b/src/test/gtest_constraint_autodiff.cpp
@@ -0,0 +1,209 @@
+/*
+ * gtest_constraint_autodiff.cpp
+ *
+ *  Created on: May 24 2017
+ *      Author: jvallve
+ */
+
+
+#include "utils_gtest.h"
+
+#include "sensor_odom_2D.h"
+#include "capture_void.h"
+#include "feature_odom_2D.h"
+#include "constraint_odom_2D.h"
+#include "constraint_odom_2D_analytic.h"
+#include "constraint_autodiff.h"
+
+using namespace wolf;
+using namespace Eigen;
+
+TEST(CaptureAutodiff, ConstructorOdom2d)
+{
+    FrameBasePtr fr1_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(2), std::make_shared<StateBlock>(1)));
+    FrameBasePtr fr2_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(2), std::make_shared<StateBlock>(1)));
+
+    // SENSOR
+    SensorOdom2DPtr sensor_ptr = std::make_shared<SensorOdom2D>(std::make_shared<StateBlock>(2), std::make_shared<StateBlock>(1), 0.1, 0.1);
+
+    // CAPTURE
+    CaptureVoidPtr capture_ptr = std::make_shared<CaptureVoid>(TimeStamp(0), sensor_ptr);
+    fr2_ptr->addCapture(capture_ptr);
+
+    // FEATURE
+    FeatureBasePtr feature_ptr = std::make_shared<FeatureOdom2D>(Eigen::Vector3s::Zero(), Eigen::Matrix3s::Identity());
+    capture_ptr->addFeature(feature_ptr);
+
+    // CONSTRAINT
+    ConstraintOdom2DPtr constraint_ptr = std::make_shared<ConstraintOdom2D>(feature_ptr, fr1_ptr);
+    feature_ptr->addConstraint(constraint_ptr);
+    fr1_ptr->addConstrainedBy(constraint_ptr);
+
+    ASSERT_TRUE(constraint_ptr->getFeaturePtr());
+    ASSERT_TRUE(constraint_ptr->getFeaturePtr()->getCapturePtr());
+    ASSERT_TRUE(constraint_ptr->getFeaturePtr()->getCapturePtr()->getFramePtr());
+    ASSERT_TRUE(constraint_ptr->getFeaturePtr()->getCapturePtr()->getSensorPtr());
+    ASSERT_TRUE(constraint_ptr->getFrameOtherPtr());
+}
+
+TEST(CaptureAutodiff, ResidualOdom2d)
+{
+    Eigen::Vector3s f1_pose, f2_pose;
+    f1_pose << 2,1,M_PI;
+    f2_pose << 3,5,3*M_PI/2;
+
+    FrameBasePtr fr1_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(f1_pose.head<2>()), std::make_shared<StateBlock>(f1_pose.tail<1>())));
+    FrameBasePtr fr2_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(f2_pose.head<2>()), std::make_shared<StateBlock>(f2_pose.tail<1>())));
+
+    // SENSOR
+    SensorOdom2DPtr sensor_ptr = std::make_shared<SensorOdom2D>(std::make_shared<StateBlock>(2), std::make_shared<StateBlock>(1), 0.1, 0.1);
+
+    // CAPTURE
+    CaptureVoidPtr capture_ptr = std::make_shared<CaptureVoid>(TimeStamp(0), sensor_ptr);
+    fr2_ptr->addCapture(capture_ptr);
+
+    // FEATURE
+    Eigen::Vector3s d;
+    d << -1, -4, M_PI/2;
+    FeatureBasePtr feature_ptr = std::make_shared<FeatureOdom2D>(d, Eigen::Matrix3s::Identity());
+    capture_ptr->addFeature(feature_ptr);
+
+    // CONSTRAINT
+    ConstraintOdom2DPtr constraint_ptr = std::make_shared<ConstraintOdom2D>(feature_ptr, fr1_ptr);
+    feature_ptr->addConstraint(constraint_ptr);
+    fr1_ptr->addConstrainedBy(constraint_ptr);
+
+    // EVALUATE
+    std::vector<Scalar*> states_ptr({fr1_ptr->getPPtr()->getPtr(), fr1_ptr->getOPtr()->getPtr(), fr2_ptr->getPPtr()->getPtr(), fr2_ptr->getOPtr()->getPtr()});
+    double const* const* parameters = states_ptr.data();
+    Eigen::VectorXs residuals(constraint_ptr->getSize());
+    constraint_ptr->evaluate(parameters, residuals.data(), nullptr);
+
+    ASSERT_TRUE(residuals.maxCoeff() < 1e-9);
+    ASSERT_TRUE(residuals.minCoeff() > -1e-9);
+}
+
+TEST(CaptureAutodiff, JacobianOdom2d)
+{
+    Eigen::Vector3s f1_pose, f2_pose;
+    f1_pose << 2,1,M_PI;
+    f2_pose << 3,5,3*M_PI/2;
+
+    FrameBasePtr fr1_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(f1_pose.head<2>()), std::make_shared<StateBlock>(f1_pose.tail<1>())));
+    FrameBasePtr fr2_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(f2_pose.head<2>()), std::make_shared<StateBlock>(f2_pose.tail<1>())));
+
+    // SENSOR
+    SensorOdom2DPtr sensor_ptr = std::make_shared<SensorOdom2D>(std::make_shared<StateBlock>(2), std::make_shared<StateBlock>(1), 0.1, 0.1);
+
+    // CAPTURE
+    CaptureVoidPtr capture_ptr = std::make_shared<CaptureVoid>(TimeStamp(0), sensor_ptr);
+    fr2_ptr->addCapture(capture_ptr);
+
+    // FEATURE
+    Eigen::Vector3s d;
+    d << -1, -4, M_PI/2;
+    FeatureBasePtr feature_ptr = std::make_shared<FeatureOdom2D>(d, Eigen::Matrix3s::Identity());
+    capture_ptr->addFeature(feature_ptr);
+
+    // CONSTRAINT
+    ConstraintOdom2DPtr constraint_ptr = std::make_shared<ConstraintOdom2D>(feature_ptr, fr1_ptr);
+    feature_ptr->addConstraint(constraint_ptr);
+    fr1_ptr->addConstrainedBy(constraint_ptr);
+
+    // COMPUTE JACOBIANS
+    std::vector<const Scalar*> states_ptr({fr1_ptr->getPPtr()->getPtr(), fr1_ptr->getOPtr()->getPtr(), fr2_ptr->getPPtr()->getPtr(), fr2_ptr->getOPtr()->getPtr()});
+    std::vector<Eigen::MatrixXs> Jauto;
+    Eigen::VectorXs residuals(constraint_ptr->getSize());
+    constraint_ptr->evaluate(states_ptr, residuals, Jauto);
+
+    std::cout << Jauto.size() << std::endl;
+
+    // ANALYTIC JACOBIANS
+    Eigen::MatrixXs J0(3,2);
+    J0 << -cos(f1_pose(2)), -sin(f1_pose(2)),
+           sin(f1_pose(2)), -cos(f1_pose(2)),
+           0,                0;
+    ASSERT_MATRIX_APPROX(J0, Jauto[0], wolf::Constants::EPS);
+    //ASSERT_TRUE((J0-Jauto[0]).maxCoeff() < 1e-9 && (J0-Jauto[0]).minCoeff() > -1e-9);
+
+    Eigen::MatrixXs J1(3,1);
+    J1 << -(f2_pose(0) - f1_pose(0)) * sin(f1_pose(2)) + (f2_pose(1) - f1_pose(1)) * cos(f1_pose(2)),
+          -(f2_pose(0) - f1_pose(0)) * cos(f1_pose(2)) - (f2_pose(1) - f1_pose(1)) * sin(f1_pose(2)),
+          -1;
+    ASSERT_MATRIX_APPROX(J1, Jauto[1], wolf::Constants::EPS);
+    //ASSERT_TRUE((J1-Jauto[1]).maxCoeff() < 1e-9 && (J1-Jauto[1]).minCoeff() > -1e-9);
+
+    Eigen::MatrixXs J2(3,2);
+    J2 <<  cos(f1_pose(2)), sin(f1_pose(2)),
+           -sin(f1_pose(2)), cos(f1_pose(2)),
+           0,               0;
+    ASSERT_MATRIX_APPROX(J2, Jauto[2], wolf::Constants::EPS);
+    //ASSERT_TRUE((J2-Jauto[2]).maxCoeff() < 1e-9 && (J2-Jauto[2]).minCoeff() > -1e-9);
+
+    Eigen::MatrixXs J3(3,1);
+    J3 <<  0, 0, 1;
+    ASSERT_MATRIX_APPROX(J3, Jauto[3], wolf::Constants::EPS);
+    //ASSERT_TRUE((J3-Jauto[3]).maxCoeff() < 1e-9 && (J3-Jauto[3]).minCoeff() > -1e-9);
+
+//    std::cout << "autodiff J " << 0 << ":\n" << Jauto[0] << std::endl;
+//    std::cout << "analytic J " << 0 << ":\n" << J0 << std::endl;
+//    std::cout << "autodiff J " << 1 << ":\n" << Jauto[1] << std::endl;
+//    std::cout << "analytic J " << 1 << ":\n" << J1 << std::endl;
+//    std::cout << "autodiff J " << 2 << ":\n" << Jauto[2] << std::endl;
+//    std::cout << "analytic J " << 2 << ":\n" << J2 << std::endl;
+//    std::cout << "autodiff J " << 3 << ":\n" << Jauto[3] << std::endl;
+//    std::cout << "analytic J " << 3 << ":\n" << J3 << std::endl;
+}
+
+TEST(CaptureAutodiff, AutodiffVsAnalytic)
+{
+    Eigen::Vector3s f1_pose, f2_pose;
+    f1_pose << 2,1,M_PI;
+    f2_pose << 3,5,3*M_PI/2;
+
+    FrameBasePtr fr1_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(f1_pose.head<2>()), std::make_shared<StateBlock>(f1_pose.tail<1>())));
+    FrameBasePtr fr2_ptr(std::make_shared<FrameBase>(TimeStamp(0), std::make_shared<StateBlock>(f2_pose.head<2>()), std::make_shared<StateBlock>(f2_pose.tail<1>())));
+
+    // SENSOR
+    SensorOdom2DPtr sensor_ptr = std::make_shared<SensorOdom2D>(std::make_shared<StateBlock>(2), std::make_shared<StateBlock>(1), 0.1, 0.1);
+
+    // CAPTURE
+    CaptureVoidPtr capture_ptr = std::make_shared<CaptureVoid>(TimeStamp(0), sensor_ptr);
+    fr2_ptr->addCapture(capture_ptr);
+
+    // FEATURE
+    Eigen::Vector3s d;
+    d << -1, -4, M_PI/2;
+    FeatureBasePtr feature_ptr = std::make_shared<FeatureOdom2D>(d, Eigen::Matrix3s::Identity());
+    capture_ptr->addFeature(feature_ptr);
+
+    // CONSTRAINTS
+    ConstraintOdom2DPtr ctr_autodiff_ptr = std::make_shared<ConstraintOdom2D>(feature_ptr, fr1_ptr);
+    feature_ptr->addConstraint(ctr_autodiff_ptr);
+    fr1_ptr->addConstrainedBy(ctr_autodiff_ptr);
+    ConstraintOdom2DAnalyticPtr ctr_analytic_ptr = std::make_shared<ConstraintOdom2DAnalytic>(feature_ptr, fr1_ptr);
+    feature_ptr->addConstraint(ctr_analytic_ptr);
+    fr1_ptr->addConstrainedBy(ctr_analytic_ptr);
+
+    // COMPUTE JACOBIANS
+    std::vector<const Scalar*> states_ptr({fr1_ptr->getPPtr()->getPtr(), fr1_ptr->getOPtr()->getPtr(), fr2_ptr->getPPtr()->getPtr(), fr2_ptr->getOPtr()->getPtr()});
+    std::vector<Eigen::MatrixXs> Jautodiff, Janalytic;
+    Eigen::VectorXs residuals(ctr_autodiff_ptr->getSize());
+    clock_t t = clock();
+    ctr_autodiff_ptr->evaluate(states_ptr, residuals, Jautodiff);
+    std::cout << "autodiff evaluate: " << ((double) clock() - t) / CLOCKS_PER_SEC << "s" << std::endl;
+    t = clock();
+    //TODO ConstraintAnalytic::evaluate
+//    ctr_analytic_ptr->evaluate(states_ptr, residuals, Janalytic);
+//    std::cout << "analytic evaluate: " << ((double) clock() - t) / CLOCKS_PER_SEC << "s" << std::endl;
+//
+//    for (auto i = 0; i < Jautodiff.size(); i++)
+//        ASSERT_MATRIX_APPROX(Jautodiff[i], Janalytic[i], wolf::Constants::EPS);
+}
+
+int main(int argc, char **argv)
+{
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
+
diff --git a/src/test/gtest_constraint_fix.cpp b/src/test/gtest_constraint_fix.cpp
index 4bafe16545e6768e21985dbe5567b18278b662f2..eaa454d6aec4a8a0a7857587940d7bc9ea66b3eb 100644
--- a/src/test/gtest_constraint_fix.cpp
+++ b/src/test/gtest_constraint_fix.cpp
@@ -59,7 +59,7 @@ TEST(ConstraintFix, solve)
     frm0->setState(x0);
 
     // solve for frm0
-    ceres::Solver::Summary summary = ceres_mgr.solve();
+    std::string report = ceres_mgr.solve(0); // 0: nothing, 1: BriefReport, 2: FullReport
 
     ASSERT_MATRIX_APPROX(frm0->getState(), pose, 1e-6);
 
diff --git a/src/test/gtest_constraint_fix_3D.cpp b/src/test/gtest_constraint_fix_3D.cpp
index b2bcc8d9332d53bbd672c98903699440d01bc598..126b1a081f5a8c731a8355dba8106ddd9ff5a0a7 100644
--- a/src/test/gtest_constraint_fix_3D.cpp
+++ b/src/test/gtest_constraint_fix_3D.cpp
@@ -67,7 +67,7 @@ TEST(ConstraintFix3D, solve)
     frm0->setState(x0);
 
     // solve for frm0
-    ceres::Solver::Summary summary = ceres_mgr.solve();
+    std::string brief_report = ceres_mgr.solve(1);
 
     ASSERT_MATRIX_APPROX(frm0->getState(), pose7, 1e-6);
 
diff --git a/src/test/gtest_constraint_imu.cpp b/src/test/gtest_constraint_imu.cpp
index 174e4783a48e9313c5ce3fc08c8e326de55ab6b0..4c19834f3af6c1edcf8ae4951d67a49f3ea4167a 100644
--- a/src/test/gtest_constraint_imu.cpp
+++ b/src/test/gtest_constraint_imu.cpp
@@ -69,7 +69,7 @@ class ConstraintIMU_biasTest_Static_NullBias : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -154,7 +154,7 @@ class ConstraintIMU_biasTest_Static_NonNullAccBias : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -239,7 +239,7 @@ class ConstraintIMU_biasTest_Static_NonNullGyroBias : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -325,7 +325,7 @@ class ConstraintIMU_biasTest_Static_NonNullBias : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -410,7 +410,7 @@ class ConstraintIMU_biasTest_Move_NullBias : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -499,7 +499,7 @@ class ConstraintIMU_biasTest_Move_NonNullBias : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -584,7 +584,7 @@ class ConstraintIMU_biasTest_Move_NonNullBiasRotCst : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -678,7 +678,7 @@ class ConstraintIMU_biasTest_Move_NonNullBiasRotAndVCst : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -780,7 +780,7 @@ class ConstraintIMU_biasTest_Move_NonNullBiasRot : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION;
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -881,7 +881,7 @@ class ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRot : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION;
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -1017,7 +1017,7 @@ class ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRot2 : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION;
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -1156,7 +1156,7 @@ class ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRotY : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION;
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -1291,7 +1291,7 @@ class ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRotXY : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION;
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -1491,7 +1491,7 @@ class ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex : public testing::Test
         ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -1650,7 +1650,7 @@ class ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex_initOK : public testin
         ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -1809,7 +1809,7 @@ class ConstraintIMU_ODOM_biasTest_Static_NullBiasNoisyComplex_initOK : public te
         ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -1968,7 +1968,7 @@ class ConstraintIMU_ODOM_biasTest_Move_BiasedNoisyComplex_initOK : public testin
         ceres_options.minimizer_type = ceres::TRUST_REGION; //ceres::TRUST_REGION;ceres::LINE_SEARCH
         ceres_options.max_line_search_step_contraction = 1e-3;
         ceres_options.max_num_iterations = 1e4;
-        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options, true);
+        ceres_manager_wolf_diff = new CeresManager(wolf_problem_ptr_, ceres_options);
 
         // SENSOR + PROCESSOR IMU
         SensorBasePtr sen0_ptr = wolf_problem_ptr_->installSensor("IMU", "Main IMU", (Vector7s()<<0,0,0,0,0,0,1).finished(), wolf_root + "/src/examples/sensor_imu.yaml");
@@ -2091,7 +2091,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NullBias,VarB1B2_InvarP1Q1V1P2Q2V2_initOK)
 
     //wolf_problem_ptr_->print(1,1,1,1);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //wolf_problem_ptr_->print(1,1,1,1);
 
@@ -2115,7 +2115,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias)
 
     wolf::Scalar epsilon_bias = 0.0000001;
     Eigen::VectorXs perturbated_origin_state(x_origin);
-    ceres::Solver::Summary summary;
+    std::string report;
 
     //==============================================================
     //WOLF_INFO("Starting error bias 1e-6")
@@ -2127,7 +2127,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias)
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2145,7 +2145,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias)
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2163,7 +2163,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias)
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2183,7 +2183,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias)
         origin_KF->setState(perturbated_origin_state);
         last_KF->setState(expected_final_state);
 
-        summary = ceres_manager_wolf_diff->solve();
+        report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
         //Only biases are unfixed
         ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2207,7 +2207,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullAccBias,VarB1B2_InvarP1Q1V1P2Q2V2_in
     last_KF->getOPtr()->fix();
     last_KF->getVPtr()->fix();
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2229,7 +2229,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullAccBias,VarB1B2_InvarP1Q1V1P2Q2V2_Er
 
     wolf::Scalar epsilon_bias = 0.0000001;
     Eigen::VectorXs perturbated_origin_state(x_origin);
-    ceres::Solver::Summary summary;
+    std::string report;
 
     //==============================================================
     //WOLF_INFO("Starting error bias 1e-6")
@@ -2241,7 +2241,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullAccBias,VarB1B2_InvarP1Q1V1P2Q2V2_Er
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2259,7 +2259,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullAccBias,VarB1B2_InvarP1Q1V1P2Q2V2_Er
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2277,7 +2277,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullAccBias,VarB1B2_InvarP1Q1V1P2Q2V2_Er
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2297,7 +2297,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullAccBias,VarB1B2_InvarP1Q1V1P2Q2V2_Er
         origin_KF->setState(perturbated_origin_state);
         last_KF->setState(expected_final_state);
 
-        summary = ceres_manager_wolf_diff->solve();
+        report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
         //Only biases are unfixed
         ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2321,7 +2321,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullGyroBias,VarB1B2_InvarP1Q1V1P2Q2V2_i
     last_KF->getOPtr()->fix();
     last_KF->getVPtr()->fix();
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2343,7 +2343,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullGyroBias,VarB1B2_InvarP1Q1V1P2Q2V2_E
 
     wolf::Scalar epsilon_bias = 0.0000001;
     Eigen::VectorXs perturbated_origin_state(x_origin);
-    ceres::Solver::Summary summary;
+    std::string report;
 
     //==============================================================
     //WOLF_INFO("Starting error bias 1e-6")
@@ -2355,7 +2355,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullGyroBias,VarB1B2_InvarP1Q1V1P2Q2V2_E
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2373,7 +2373,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullGyroBias,VarB1B2_InvarP1Q1V1P2Q2V2_E
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2391,7 +2391,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullGyroBias,VarB1B2_InvarP1Q1V1P2Q2V2_E
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2411,7 +2411,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullGyroBias,VarB1B2_InvarP1Q1V1P2Q2V2_E
         origin_KF->setState(perturbated_origin_state);
         last_KF->setState(expected_final_state);
 
-        summary = ceres_manager_wolf_diff->solve();
+        report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
         //Only biases are unfixed
         ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2434,7 +2434,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBi
 
     wolf::Scalar epsilon_bias = 0.0000001;
     Eigen::VectorXs perturbated_origin_state(x_origin);
-    ceres::Solver::Summary summary;
+    std::string report;
 
     //==============================================================
     //WOLF_INFO("Starting error bias 1e-6")
@@ -2446,7 +2446,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBi
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2464,7 +2464,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBi
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2482,7 +2482,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBi
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2502,7 +2502,7 @@ TEST_F(ConstraintIMU_biasTest_Static_NonNullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBi
         origin_KF->setState(perturbated_origin_state);
         last_KF->setState(expected_final_state);
 
-        summary = ceres_manager_wolf_diff->solve();
+        report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport;
 
         //Only biases are unfixed
         ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2526,7 +2526,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NullBias,VarB1B2_InvarP1Q1V1P2Q2V2_initOK)
     last_KF->getOPtr()->fix();
     last_KF->getVPtr()->fix();
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2548,7 +2548,6 @@ TEST_F(ConstraintIMU_biasTest_Move_NullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias)
 
     wolf::Scalar epsilon_bias = 0.0000001;
     Eigen::VectorXs perturbated_origin_state(x_origin);
-    ceres::Solver::Summary summary;
 
     //==============================================================
     //WOLF_INFO("Starting error bias 1e-6")
@@ -2560,7 +2559,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias)
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2578,7 +2577,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias)
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2596,7 +2595,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias)
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2616,7 +2615,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias)
         origin_KF->setState(perturbated_origin_state);
         last_KF->setState(expected_final_state);
 
-        summary = ceres_manager_wolf_diff->solve();
+        report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport
 
         //Only biases are unfixed
         ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2642,7 +2641,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBias,VarB1B2_InvarP1Q1V1P2Q2V2_initOK)
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport
 
    // wolf_problem_ptr_->print(4,1,1,1);
 
@@ -2666,7 +2665,6 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias
 
     wolf::Scalar epsilon_bias = 0.0000001;
     Eigen::VectorXs perturbated_origin_state(x_origin);
-    ceres::Solver::Summary summary;
 
     //==============================================================
     //WOLF_INFO("Starting error bias 1e-6")
@@ -2678,7 +2676,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1); // 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2696,7 +2694,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2714,7 +2712,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2734,7 +2732,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBias,VarB1B2_InvarP1Q1V1P2Q2V2_ErrBias
         origin_KF->setState(perturbated_origin_state);
         last_KF->setState(expected_final_state);
 
-        summary = ceres_manager_wolf_diff->solve();
+        report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
         //Only biases are unfixed
         ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2760,7 +2758,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRotCst,VarB1B2_InvarP1Q1V1P2Q2V2_i
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
@@ -2784,7 +2782,6 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRotCst,VarB1B2_InvarP1Q1V1P2Q2V2_E
 
     wolf::Scalar epsilon_bias = 0.0000001;
     Eigen::VectorXs perturbated_origin_state(x_origin);
-    ceres::Solver::Summary summary;
 
     //==============================================================
     //WOLF_INFO("Starting error bias 1e-6")
@@ -2796,7 +2793,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRotCst,VarB1B2_InvarP1Q1V1P2Q2V2_E
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2814,7 +2811,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRotCst,VarB1B2_InvarP1Q1V1P2Q2V2_E
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2832,7 +2829,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRotCst,VarB1B2_InvarP1Q1V1P2Q2V2_E
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2852,7 +2849,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRotCst,VarB1B2_InvarP1Q1V1P2Q2V2_E
         origin_KF->setState(perturbated_origin_state);
         last_KF->setState(expected_final_state);
 
-        summary = ceres_manager_wolf_diff->solve();
+        report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
         //Only biases are unfixed
         ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2878,7 +2875,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRotAndVCst,VarB1B2_InvarP1Q1V1P2Q2
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
@@ -2902,7 +2899,6 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRotAndVCst,VarB1B2_InvarP1Q1V1P2Q2
 
     wolf::Scalar epsilon_bias = 0.0000001;
     Eigen::VectorXs perturbated_origin_state(x_origin);
-    ceres::Solver::Summary summary;
 
     //==============================================================
     //WOLF_INFO("Starting error bias 1e-6")
@@ -2914,7 +2910,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRotAndVCst,VarB1B2_InvarP1Q1V1P2Q2
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2932,7 +2928,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRotAndVCst,VarB1B2_InvarP1Q1V1P2Q2
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2950,7 +2946,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRotAndVCst,VarB1B2_InvarP1Q1V1P2Q2
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2970,7 +2966,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRotAndVCst,VarB1B2_InvarP1Q1V1P2Q2
         origin_KF->setState(perturbated_origin_state);
         last_KF->setState(expected_final_state);
 
-        summary = ceres_manager_wolf_diff->solve();
+        report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
         //Only biases are unfixed
         ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -2994,7 +2990,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRotAndVCst, VarB1B2V1P2V2_InvarP1Q
     last_KF->getOPtr()->fix();
     last_KF->getVPtr()->unfix();
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -3019,7 +3015,7 @@ TEST_F(ConstraintIMU_biasTest_Move_NonNullBiasRot, VarB1B2V1P2V2_InvarP1Q1Q2_ini
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
@@ -3053,7 +3049,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRotY, VarB1B2_InvarP1Q1V1P2Q2
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
 
     //wolf_problem_ptr_->print(4,1,1,1);
@@ -3105,7 +3101,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRotY, VarB1B2V2_InvarP1Q1V1P2
     origin_KF->getAccBiasPtr()->setState(accBias + random_err);
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
 
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -3156,7 +3152,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRotY, VarB1B2V1V2_InvarP1Q1P2
     origin_KF->getAccBiasPtr()->setState(accBias + random_err);
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     //ceres_manager_wolf_diff->computeCovariances(ALL);
 
     ASSERT_MATRIX_APPROX(origin_KF->getVPtr()->getState(), x_origin.segment(7,3), wolf::Constants::EPS*1000)
@@ -3189,7 +3185,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRotY, VarB1B2V1Q2V2_InvarP1Q1
     origin_KF->getAccBiasPtr()->setState(accBias + random_err);
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     ASSERT_MATRIX_APPROX(origin_KF->getVPtr()->getState(), x_origin.segment(7,3), wolf::Constants::EPS*1000)
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), 0.00001)
@@ -3223,7 +3219,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRotY, VarB1B2V1P2V2_InvarP1Q1
     origin_KF->getAccBiasPtr()->setState(accBias + random_err);
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     ASSERT_MATRIX_APPROX(origin_KF->getVPtr()->getState(), x_origin.segment(7,3), wolf::Constants::EPS*1000)
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), 0.00001)
@@ -3256,7 +3252,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRotY, VarB1B2V1P2Q2V2_InvarP1
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
     //wolf_problem_ptr_->print(4,1,1,1);
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     //wolf_problem_ptr_->print(4,1,1,1);
 
     ASSERT_MATRIX_APPROX(origin_KF->getVPtr()->getState(), x_origin.segment(7,3), wolf::Constants::EPS*10000)
@@ -3290,7 +3286,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRotY, VarB1B2P2Q2V2_InvarP1Q1
     origin_KF->getAccBiasPtr()->setState(accBias + random_err);
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
 
     ASSERT_MATRIX_APPROX(origin_KF->getVPtr()->getState(), x_origin.segment(7,3), wolf::Constants::EPS*1000)
@@ -3352,7 +3348,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRotY, VarQ1B1B2P2Q2_InvarP1V1
     origin_KF->getAccBiasPtr()->setState(accBias + random_err);
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
 
     ASSERT_MATRIX_APPROX(origin_KF->getVPtr()->getState(), x_origin.segment(7,3), wolf::Constants::EPS*1000)
@@ -3414,7 +3410,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRotXY, VarQ1B1B2P2Q2_InvarP1V
     origin_KF->getAccBiasPtr()->setState(accBias + random_err);
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
 
     ASSERT_MATRIX_APPROX(origin_KF->getVPtr()->getState(), x_origin.segment(7,3), wolf::Constants::EPS*1000)
@@ -3470,7 +3466,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRot, VarB1B2_InvarP1Q1V1P2Q2V
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
 
     //wolf_problem_ptr_->print(4,1,1,1);
@@ -3522,7 +3518,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRot, VarB1B2V2_InvarP1Q1V1P2Q
     origin_KF->getAccBiasPtr()->setState(accBias + random_err);
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
 
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -3572,7 +3568,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRot, VarB1B2V1V2_InvarP1Q1P2Q
     origin_KF->getAccBiasPtr()->setState(accBias + random_err);
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     ASSERT_MATRIX_APPROX(origin_KF->getVPtr()->getState(), x_origin.segment(7,3), wolf::Constants::EPS*1000)
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), 0.00001)
@@ -3603,7 +3599,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRot, VarB1B2V1Q2V2_InvarP1Q1P
     origin_KF->getAccBiasPtr()->setState(accBias + random_err);
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     ASSERT_MATRIX_APPROX(origin_KF->getVPtr()->getState(), x_origin.segment(7,3), wolf::Constants::EPS*1000)
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), 0.00001)
@@ -3636,7 +3632,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRot, VarB1B2V1P2V2_InvarP1Q1Q
     origin_KF->getAccBiasPtr()->setState(accBias + random_err);
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     ASSERT_MATRIX_APPROX(origin_KF->getVPtr()->getState(), x_origin.segment(7,3), wolf::Constants::EPS*1000)
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), 0.00001)
@@ -3668,7 +3664,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRot, VarB1B2V1P2Q2V2_InvarP1Q
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
     //wolf_problem_ptr_->print(4,1,1,1);
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     //wolf_problem_ptr_->print(4,1,1,1);
 
     ASSERT_MATRIX_APPROX(origin_KF->getVPtr()->getState(), x_origin.segment(7,3), wolf::Constants::EPS*10000)
@@ -3702,7 +3698,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRot, VarB1B2P2Q2V2_InvarP1Q1V
     origin_KF->getAccBiasPtr()->setState(accBias + random_err);
     origin_KF->getGyroBiasPtr()->setState(gyroBias + random_err);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
 
     ASSERT_MATRIX_APPROX(origin_KF->getVPtr()->getState(), x_origin.segment(7,3), wolf::Constants::EPS*1000)
@@ -3750,7 +3746,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasRot, VarB1B2P2Q2V2_InvarP1Q1V
     last_KF->getOPtr()->unfix();
     last_KF->getVPtr()->unfix();
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     ASSERT_MATRIX_APPROX(origin_KF->getPPtr()->getState(), x_origin.head(3), wolf::Constants::EPS*100)
     Eigen::Map<const Eigen::Quaternions> estimatedOriginQuat(origin_KF->getOPtr()->getState().data()), expectedOriginQuat(x_origin.segment(3,4).data());
@@ -3788,7 +3784,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex_initOK, VarB1B2_Invar
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     WOLF_WARN("Precision set to ", 0.001)
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), 0.001)
@@ -3819,7 +3815,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex_initOK, VarB1B2P2Q2_I
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     WOLF_WARN("Precision set to ", 0.001)
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), 0.001)
@@ -3853,7 +3849,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex_initOK, VarB1B2P2Q2V2
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     WOLF_WARN("Precision set to ", 0.0001)
 
@@ -3889,7 +3885,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex_initOK, VarAll)
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     WOLF_WARN("Precision set to ", 0.001)
 
@@ -3929,7 +3925,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex, VarB1B2_InvarP1Q1V1P
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
     //ASSERT_MATRIX_APPROX(origin_KF->getGyroBiasPtr()->getState(), origin_bias.tail(3), wolf::Constants::EPS*100)
@@ -3976,7 +3972,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex, VarB1B2P2Q2V2_InvarP
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
 
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -4028,7 +4024,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex, VarB1B2_InvarP1Q1V1P
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
 
     /*ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), wolf::Constants::EPS*100)
@@ -4067,7 +4063,6 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex_initOK,VarB1B2_InvarP
 
     wolf::Scalar epsilon_bias = 0.0000001;
     Eigen::VectorXs perturbated_origin_state(x_origin);
-    ceres::Solver::Summary summary;
 
     //==============================================================
     //WOLF_INFO("Starting error bias 1e-6")
@@ -4079,7 +4074,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex_initOK,VarB1B2_InvarP
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     WOLF_WARN("Precision set to ", 0.001)
 
     //Only biases are unfixed
@@ -4098,7 +4093,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex_initOK,VarB1B2_InvarP
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), 0.001)
@@ -4116,7 +4111,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex_initOK,VarB1B2_InvarP
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    summary = ceres_manager_wolf_diff->solve();
+    report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
     //Only biases are unfixed
     ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), 0.001)
@@ -4136,7 +4131,7 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_NonNullBiasComplex_initOK,VarB1B2_InvarP
         origin_KF->setState(perturbated_origin_state);
         last_KF->setState(expected_final_state);
 
-        summary = ceres_manager_wolf_diff->solve();
+        report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
 
         //Only biases are unfixed
         ASSERT_MATRIX_APPROX(origin_KF->getAccBiasPtr()->getState(), origin_bias.head(3), 0.001)
@@ -4172,9 +4167,9 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Static_NullBiasNoisyComplex_initOK, varB1B2P2
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
-    std::cout << summary.BriefReport() << std::endl;
+    std::cout << report << std::endl;
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
@@ -4229,9 +4224,9 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Static_NullBiasNoisyComplex_initOK, varQ1B1P2
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
-    std::cout << summary.BriefReport() << std::endl;
+    std::cout << report << std::endl;
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
@@ -4285,10 +4280,9 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Static_NullBiasNoisyComplex_initOK, varB1B2_i
     last_KF->setState(expected_final_state);
 
     //wolf_problem_ptr_->print(4,1,1,1);
-
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
-    std::cout << summary.BriefReport() << std::endl;
+    std::cout << report << std::endl;
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
@@ -4340,9 +4334,9 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_BiasedNoisyComplex_initOK, varB1P2Q2V2B2
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
-    std::cout << summary.BriefReport() << std::endl;
+    std::cout << report << std::endl;
 
     //These ASSERTS can be removed since we are more interested in using covariances to make sure that expected values are inside estimated +/- 2*std
     WOLF_WARN("Precision set to ", 0.01)
@@ -4405,9 +4399,9 @@ TEST_F(ConstraintIMU_ODOM_biasTest_Move_BiasedNoisyComplex_initOK, varQ1B1P2Q2B2
     origin_KF->setState(perturbated_origin_state);
     last_KF->setState(expected_final_state);
 
-    ceres::Solver::Summary summary = ceres_manager_wolf_diff->solve();
+    std::string report = ceres_manager_wolf_diff->solve(1);// 0: nothing, 1: BriefReport, 2: FullReport
     ceres_manager_wolf_diff->computeCovariances(ALL);
-    std::cout << summary.BriefReport() << std::endl;
+    std::cout << report << std::endl;
 
     //wolf_problem_ptr_->print(4,1,1,1);
 
diff --git a/src/test/gtest_constraint_odom_3D.cpp b/src/test/gtest_constraint_odom_3D.cpp
index 39afa2989534989c9f7c787e356ce91e9b98dc37..077568e260e28f83d9aabdc1e16699de827252d1 100644
--- a/src/test/gtest_constraint_odom_3D.cpp
+++ b/src/test/gtest_constraint_odom_3D.cpp
@@ -69,7 +69,7 @@ TEST(ConstraintOdom3D, fix_0_solve)
     frm1->setState(x1);
 
     // solve for frm1
-    ceres::Solver::Summary summary = ceres_mgr.solve();
+    std::string report = ceres_mgr.solve(1);
 
     ASSERT_MATRIX_APPROX(frm1->getState(), delta, 1e-6);
 
@@ -83,7 +83,7 @@ TEST(ConstraintOdom3D, fix_1_solve)
     frm0->setState(x0);
 
     // solve for frm0
-    ceres::Solver::Summary summary = ceres_mgr.solve();
+    std::string brief_report = ceres_mgr.solve(1);
 
     ASSERT_MATRIX_APPROX(frm0->getState(), problem->zeroState(), 1e-6);
 }
diff --git a/src/test/gtest_odom_2D.cpp b/src/test/gtest_odom_2D.cpp
index 59f549cd20c60fe03e5949583a6ce92b6f0fedff..eac322008965686b4b63458258de20a1c62af99e 100644
--- a/src/test/gtest_odom_2D.cpp
+++ b/src/test/gtest_odom_2D.cpp
@@ -125,7 +125,6 @@ TEST(Odom2D, ConstraintFix_and_ConstraintOdom2D)
 
     ProblemPtr          Pr = Problem::create("PO 2D");
     CeresManager ceres_manager(Pr);
-    ceres::Solver::Summary summary;
 
     // KF0 and absolute prior
     FrameBasePtr        F0 = Pr->setPrior(x0, P0,t0);
@@ -154,9 +153,9 @@ TEST(Odom2D, ConstraintFix_and_ConstraintOdom2D)
     F0->setState(Vector3s(1,2,3));
     F1->setState(Vector3s(2,3,1));
     F2->setState(Vector3s(3,1,2));
-    summary = ceres_manager.solve();
-//    std::cout << summary.BriefReport() << std::endl;
-//    std::cout << summary.FullReport() << std::endl;
+    std::string report = ceres_manager.solve(1);
+//    std::cout << report << std::endl;
+
     ceres_manager.computeCovariances(ALL_MARGINALS);
 //    show(Pr);
 
@@ -212,7 +211,7 @@ TEST(Odom2D, VoteForKfAndSolve)
 
     // Origin Key Frame
     FrameBasePtr origin_frame = problem->setPrior(x0, P0, t0);
-    ceres_manager.solve();
+    ceres_manager.solve(0);
     ceres_manager.computeCovariances(ALL_MARGINALS);
 
     //    std::cout << "Initial pose : " << problem->getCurrentState().transpose() << std::endl;
@@ -281,7 +280,8 @@ TEST(Odom2D, VoteForKfAndSolve)
     }
 
     // Solve
-    ceres::Solver::Summary summary = ceres_manager.solve();
+    std::string report = ceres_manager.solve(1);
+//    std::cout << report << std::endl;
     ceres_manager.computeCovariances(ALL_MARGINALS);
 
     ASSERT_MATRIX_APPROX(problem->getLastKeyFrameCovariance() , integrated_cov_vector[5], 1e-6);
@@ -326,7 +326,6 @@ TEST(Odom2D, KF_callback)
 
     // Ceres wrapper
     CeresManager ceres_manager(problem);
-    ceres::Solver::Summary summary;
 
     // Origin Key Frame
     FrameBasePtr keyframe_0 = problem->setPrior(x0, x0_cov, t0);
@@ -399,7 +398,8 @@ TEST(Odom2D, KF_callback)
 
     MotionBuffer key_buffer_n = key_capture_n->getBuffer();
 
-    ceres_manager.solve();
+    std::string report = ceres_manager.solve(1);
+//    std::cout << report << std::endl;
     ceres_manager.computeCovariances(ALL_MARGINALS);
 
     ASSERT_POSE2D_APPROX(problem->getLastKeyFramePtr()->getState() , integrated_pose_vector[n_split], 1e-6);
@@ -428,8 +428,9 @@ TEST(Odom2D, KF_callback)
     keyframe_0->setState(Vector3s(1,2,3));
     keyframe_1->setState(Vector3s(2,3,1));
     keyframe_2->setState(Vector3s(3,1,2));
-    summary = ceres_manager.solve();
-//    std::cout << summary.BriefReport() << std::endl;
+
+    report = ceres_manager.solve(1);
+//    std::cout << report << std::endl;
     ceres_manager.computeCovariances(ALL_MARGINALS);
 //    show(problem);
 
diff --git a/src/wolf.h b/src/wolf.h
index 0e945f49d9ea47c7ed4c73657c4e9f44f77977c4..cb8094e01f79df77b34032191276f32bb493a968 100644
--- a/src/wolf.h
+++ b/src/wolf.h
@@ -109,6 +109,9 @@ typedef Transform<wolf::Scalar,3,Affine> Affine3ds;         ///< Affine3d of rea
 
 typedef Transform<wolf::Scalar,2,Isometry> Isometry2ds;     ///< Isometry2d of real Scalar type
 typedef Transform<wolf::Scalar,3,Isometry> Isometry3ds;     ///< Isometry3d of real Scalar type
+
+// 3. Sparse matrix
+typedef SparseMatrix<wolf::Scalar, RowMajor, int> SparseMatrixs;
 }
 
 namespace wolf {