diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9ae5db6ed39c099a74bbd8c5e8de2ebd4c7ec3e9..3cfdcb44eff879f3ea3934c3a79fc9ec6c4f4fd5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -246,6 +246,7 @@ SET(HDRS_FACTOR
   include/core/factor/factor_pose_3d.h
   include/core/factor/factor_quaternion_absolute.h
   include/core/factor/factor_relative_2d_analytic.h
+  include/core/factor/factor_relative_pose_2d_with_extrinsics.h
   )
 SET(HDRS_FEATURE
   include/core/feature/feature_base.h
@@ -285,7 +286,11 @@ SET(HDRS_SOLVER
   include/core/solver/solver_manager.h
   include/core/solver/factory_solver.h
   )
-
+SET(HDRS_TREE_MANAGER
+  include/core/tree_manager/factory_tree_manager.h
+  include/core/tree_manager/tree_manager_base.h
+  include/core/tree_manager/tree_manager_sliding_window.h
+  )
 SET(HDRS_YAML
   include/core/yaml/parser_yaml.h
   include/core/yaml/yaml_conversion.h
@@ -371,6 +376,9 @@ SET(SRCS_SENSOR
 SET(SRCS_SOLVER
   src/solver/solver_manager.cpp
   )
+SET(SRCS_TREE_MANAGER
+  src/tree_manager/tree_manager_sliding_window.cpp
+  )
 SET(SRCS_YAML
   src/yaml/parser_yaml.cpp
   src/yaml/processor_odom_3d_yaml.cpp
@@ -400,8 +408,6 @@ ELSE(Ceres_FOUND)
  SET(SRCS_WRAPPER)
 ENDIF(Ceres_FOUND)
 
-#SUBDIRECTORIES
-add_subdirectory(hello_wolf)
 IF (cereal_FOUND)
 ADD_SUBDIRECTORY(serialization/cereal)
 ENDIF(cereal_FOUND)
@@ -431,6 +437,7 @@ ADD_LIBRARY(${PROJECT_NAME}
   ${SRCS_SOLVER}
   ${SRCS_STATE_BLOCK}
   ${SRCS_TRAJECTORY}
+  ${SRCS_TREE_MANAGER}
   ${SRCS_UTILS}
   ${SRCS_WRAPPER}
   ${SRCS_YAML}
@@ -471,44 +478,46 @@ INSTALL(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets
 
 install(EXPORT ${PROJECT_NAME}Targets DESTINATION lib/cmake/${PROJECT_NAME})
 #install headers
-INSTALL(FILES ${HDRS_MATH}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/math)
-INSTALL(FILES ${HDRS_UTILS}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/utils)
-INSTALL(FILES ${HDRS_PROBLEM}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/problem)
-INSTALL(FILES ${HDRS_HARDWARE}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/hardware)
-INSTALL(FILES ${HDRS_TRAJECTORY}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/trajectory)
-INSTALL(FILES ${HDRS_MAP}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/map)
-INSTALL(FILES ${HDRS_FRAME}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/frame)
-INSTALL(FILES ${HDRS_STATE_BLOCK}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/state_block)
-INSTALL(FILES ${HDRS_COMMON}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/common)
 INSTALL(FILES ${HDRS_CAPTURE}
    DESTINATION include/iri-algorithms/wolf/plugin_core/core/capture)
+INSTALL(FILES ${HDRS_COMMON}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/common)
 INSTALL(FILES ${HDRS_FACTOR}
   DESTINATION include/iri-algorithms/wolf/plugin_core/core/factor)
 INSTALL(FILES ${HDRS_FEATURE}
   DESTINATION include/iri-algorithms/wolf/plugin_core/core/feature)
-INSTALL(FILES ${HDRS_SENSOR}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/sensor)
-INSTALL(FILES ${HDRS_PROCESSOR}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/processor)
+INSTALL(FILES ${HDRS_FRAME}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/frame)
+INSTALL(FILES ${HDRS_HARDWARE}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/hardware)
 INSTALL(FILES ${HDRS_LANDMARK}
   DESTINATION include/iri-algorithms/wolf/plugin_core/core/landmark)
-INSTALL(FILES ${HDRS_WRAPPER}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/ceres_wrapper)
-INSTALL(FILES ${HDRS_SOLVER_SUITESPARSE}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/solver_suitesparse)
-INSTALL(FILES ${HDRS_SOLVER}
-  DESTINATION include/iri-algorithms/wolf/plugin_core/core/solver)
+INSTALL(FILES ${HDRS_MAP}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/map)
+INSTALL(FILES ${HDRS_MATH}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/math)
+INSTALL(FILES ${HDRS_PROBLEM}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/problem)
+INSTALL(FILES ${HDRS_PROCESSOR}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/processor)
+INSTALL(FILES ${HDRS_SENSOR}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/sensor)
 INSTALL(FILES ${HDRS_SERIALIZATION}
   DESTINATION include/iri-algorithms/wolf/plugin_core/core/serialization)
+INSTALL(FILES ${HDRS_SOLVER}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/solver)
+INSTALL(FILES ${HDRS_SOLVER_SUITESPARSE}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/solver_suitesparse)
+INSTALL(FILES ${HDRS_STATE_BLOCK}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/state_block)
+INSTALL(FILES ${HDRS_TRAJECTORY}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/trajectory)
+INSTALL(FILES ${HDRS_TREE_MANAGER}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/tree_manager)
+INSTALL(FILES ${HDRS_UTILS}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/utils)
+INSTALL(FILES ${HDRS_WRAPPER}
+  DESTINATION include/iri-algorithms/wolf/plugin_core/core/ceres_wrapper)
 INSTALL(FILES ${HDRS_YAML}
   DESTINATION include/iri-algorithms/wolf/plugin_core/core/yaml)
 
diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e6b2bb11cbe6b95dceba4095af5c57b2c76f16c0
--- /dev/null
+++ b/demos/CMakeLists.txt
@@ -0,0 +1,2 @@
+#Add hello_wolf demo
+add_subdirectory(hello_wolf)
diff --git a/demos/demo_map_yaml.cpp b/demos/demo_map_yaml.cpp
deleted file mode 100644
index 87023e52856c9e3ba937882cd5311e05260b507b..0000000000000000000000000000000000000000
--- a/demos/demo_map_yaml.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * \file test_map_yaml.cpp
- *
- *  Created on: Jul 27, 2016
- *      \author: jsola
- */
-
-#include "core/common/wolf.h"
-#include "core/problem/problem.h"
-#include "core/map/map_base.h"
-#include "core/landmark/landmark_polyline_2d.h"
-#include "core/landmark/landmark_AHP.h"
-#include "core/state_block/state_block.h"
-#include "core/yaml/yaml_conversion.h"
-
-#include <iostream>
-using namespace wolf;
-
-void print(MapBase& _map)
-{
-    for (auto lmk_ptr : _map.getLandmarkList())
-    {
-        std::cout << "Lmk ID:    " << lmk_ptr->id();
-        std::cout << "\nLmk type:  " << lmk_ptr->getType();
-        if (lmk_ptr->getType() == "POLYLINE 2d")
-        {
-            LandmarkPolyline2dPtr poly_ptr = std::static_pointer_cast<LandmarkPolyline2d>(lmk_ptr);
-            std::cout << "\npos:       " << poly_ptr->getP()->getState().transpose() << " -- fixed: " << poly_ptr->getP()->isFixed();
-            std::cout << "\nori:       " << poly_ptr->getO()->getState().transpose() << " -- fixed: " << poly_ptr->getO()->isFixed();
-            std::cout << "\nn points:  " << poly_ptr->getNPoints();
-            std::cout << "\nFirst idx: " << poly_ptr->getFirstId();
-            std::cout << "\nFirst def: " << poly_ptr->isFirstDefined();
-            std::cout << "\nLast  def: " << poly_ptr->isLastDefined();
-            for (int idx = poly_ptr->getFirstId(); idx <= poly_ptr->getLastId(); idx++)
-                std::cout << "\n  point: " << idx << ": " << poly_ptr->getPointStateBlock(idx)->getState().transpose();
-            break;
-        }
-        else if (lmk_ptr->getType() == "AHP")
-        {
-            LandmarkAHPPtr ahp_ptr = std::static_pointer_cast<LandmarkAHP>(lmk_ptr);
-            std::cout << "\npos:       " << ahp_ptr->getP()->getState().transpose() << " -- fixed: " << ahp_ptr->getP()->isFixed();
-            std::cout << "\ndescript:  " << ahp_ptr->getCvDescriptor().t();
-            break;
-        }
-        else
-            break;
-
-        std::cout << std::endl;
-    }
-}
-
-int main()
-{
-    using namespace Eigen;
-
-    std::cout << "\nTesting Lmk creator and node saving..." << std::endl;
-    Vector4d v;
-    v << 1, 2, 3, 4;
-    cv::Mat d = (cv::Mat_<int>(8,1) << 1, 2, 3, 4, 5, 6, 7, 8);
-    LandmarkAHP lmk_1(v, nullptr, nullptr, d);
-    std::cout << "Pos 1 = " << lmk_1.getP()->getState().transpose() << std::endl;
-    std::cout << "Des 1 = " << lmk_1.getCvDescriptor().t() << std::endl;
-
-    YAML::Node n = lmk_1.saveToYaml();
-    std::cout << "Pos n = " << n["position"].as<VectorXd>().transpose() << std::endl;
-    std::cout << "Des n = " << n["descriptor"].as<VectorXd>().transpose() << std::endl;
-
-    LandmarkAHP lmk_2 = *(std::static_pointer_cast<LandmarkAHP>(LandmarkAHP::create(n)));
-    std::cout << "Pos 2 = " << lmk_2.getP()->getState().transpose() << std::endl;
-    std::cout << "Des 2 = " << lmk_2.getCvDescriptor().t() << std::endl;
-
-    std::string filename;
-
-    std::string wolf_root       = _WOLF_ROOT_DIR;
-    std::string wolf_config     = wolf_root + "/src/examples";
-    std::cout << "\nWolf directory for configuration files: " << wolf_config << std::endl;
-
-    ProblemPtr problem = Problem::create("PO", 2);
-    filename = wolf_config + "/map_polyline_example.yaml";
-    std::cout << "Reading map from file: " << filename << std::endl;
-    problem->loadMap(filename);
-
-    std::cout << "Printing map..." << std::endl;
-    print(*(problem->getMap()));
-
-    filename = wolf_config + "/map_polyline_example_write.yaml";
-    std::cout << "Writing map to file: " << filename << std::endl;
-    std::string thisfile = __FILE__;
-    problem->getMap()->save(filename, "Example generated by test file " + thisfile);
-
-    std::cout << "Clearing map... " << std::endl;
-    problem->getMap()->getLandmarkList().clear();
-
-    std::cout << "Re-reading map from file: " << filename << std::endl;
-    problem->loadMap(filename);
-
-    std::cout << "Printing map..." << std::endl;
-    print(*(problem->getMap()));
-
-    return 0;
-}
diff --git a/hello_wolf/CMakeLists.txt b/demos/hello_wolf/CMakeLists.txt
similarity index 100%
rename from hello_wolf/CMakeLists.txt
rename to demos/hello_wolf/CMakeLists.txt
diff --git a/hello_wolf/capture_range_bearing.cpp b/demos/hello_wolf/capture_range_bearing.cpp
similarity index 89%
rename from hello_wolf/capture_range_bearing.cpp
rename to demos/hello_wolf/capture_range_bearing.cpp
index a2d44a101085ea0ad3aa4ae7d68af68370ea5024..9ead1c183b8b08a64f709faea5236d5dbb056231 100644
--- a/hello_wolf/capture_range_bearing.cpp
+++ b/demos/hello_wolf/capture_range_bearing.cpp
@@ -11,7 +11,7 @@ namespace wolf
 {
 
 CaptureRangeBearing::CaptureRangeBearing(const TimeStamp& _ts, const SensorBasePtr& _scanner, const Eigen::VectorXi& _ids, const Eigen::VectorXd& _ranges, const Eigen::VectorXd& _bearings) :
-        CaptureBase("RANGE BEARING", _ts, _scanner),
+        CaptureBase("CaptureRangeBearing", _ts, _scanner),
         ids_(_ids),
         ranges_(_ranges),
         bearings_(_bearings)
diff --git a/hello_wolf/capture_range_bearing.h b/demos/hello_wolf/capture_range_bearing.h
similarity index 100%
rename from hello_wolf/capture_range_bearing.h
rename to demos/hello_wolf/capture_range_bearing.h
diff --git a/hello_wolf/factor_bearing.h b/demos/hello_wolf/factor_bearing.h
similarity index 100%
rename from hello_wolf/factor_bearing.h
rename to demos/hello_wolf/factor_bearing.h
diff --git a/hello_wolf/factor_range_bearing.h b/demos/hello_wolf/factor_range_bearing.h
similarity index 100%
rename from hello_wolf/factor_range_bearing.h
rename to demos/hello_wolf/factor_range_bearing.h
diff --git a/hello_wolf/feature_range_bearing.cpp b/demos/hello_wolf/feature_range_bearing.cpp
similarity index 82%
rename from hello_wolf/feature_range_bearing.cpp
rename to demos/hello_wolf/feature_range_bearing.cpp
index 4d47cc5539f5fcfe2cc011ea4c4e6e11d2685f90..ea584a419aa21c1d7e462824d6872f7d57bd818c 100644
--- a/hello_wolf/feature_range_bearing.cpp
+++ b/demos/hello_wolf/feature_range_bearing.cpp
@@ -11,7 +11,7 @@ namespace wolf
 {
 
 FeatureRangeBearing::FeatureRangeBearing(const Eigen::VectorXd& _measurement, const Eigen::MatrixXd& _meas_covariance) :
-        FeatureBase("RANGE BEARING", _measurement, _meas_covariance)
+        FeatureBase("FeatureRangeBearing", _measurement, _meas_covariance)
 {
     //
 }
diff --git a/hello_wolf/feature_range_bearing.h b/demos/hello_wolf/feature_range_bearing.h
similarity index 100%
rename from hello_wolf/feature_range_bearing.h
rename to demos/hello_wolf/feature_range_bearing.h
diff --git a/hello_wolf/hello_wolf.cpp b/demos/hello_wolf/hello_wolf.cpp
similarity index 100%
rename from hello_wolf/hello_wolf.cpp
rename to demos/hello_wolf/hello_wolf.cpp
diff --git a/hello_wolf/hello_wolf_autoconf.cpp b/demos/hello_wolf/hello_wolf_autoconf.cpp
similarity index 99%
rename from hello_wolf/hello_wolf_autoconf.cpp
rename to demos/hello_wolf/hello_wolf_autoconf.cpp
index a387adfe9656523c37d025bb3a74f0f198281b3d..5ab1ad1dd20a6b03411ea5cc458bde99b2b1fca8 100644
--- a/hello_wolf/hello_wolf_autoconf.cpp
+++ b/demos/hello_wolf/hello_wolf_autoconf.cpp
@@ -98,7 +98,7 @@ int main()
     WOLF_TRACE("======== CONFIGURE PROBLEM =======");
 
     // Config file to parse. Here is where all the problem is defined:
-    std::string config_file = "hello_wolf/yaml/hello_wolf_config.yaml";
+    std::string config_file = "demos/hello_wolf/yaml/hello_wolf_config.yaml";
     std::string wolf_path   = std::string(_WOLF_ROOT_DIR);
 
     // parse file into params server: each param will be retrievable from this params server:
diff --git a/hello_wolf/landmark_point_2d.cpp b/demos/hello_wolf/landmark_point_2d.cpp
similarity index 80%
rename from hello_wolf/landmark_point_2d.cpp
rename to demos/hello_wolf/landmark_point_2d.cpp
index 835c4fb04e4f7b1e5695958ca9db3cbb810c5ec5..8b2ad4c0e8a9b576f67e9d8d56e41d932abedef8 100644
--- a/hello_wolf/landmark_point_2d.cpp
+++ b/demos/hello_wolf/landmark_point_2d.cpp
@@ -11,7 +11,7 @@ namespace wolf
 {
 
 LandmarkPoint2d::LandmarkPoint2d(int _id, const Eigen::Vector2d& _xy) :
-        LandmarkBase("POINT 2d", std::make_shared<StateBlock>(_xy))
+        LandmarkBase("LandmarkPoint2d", std::make_shared<StateBlock>(_xy))
 {
     setId(_id);
 }
diff --git a/hello_wolf/landmark_point_2d.h b/demos/hello_wolf/landmark_point_2d.h
similarity index 100%
rename from hello_wolf/landmark_point_2d.h
rename to demos/hello_wolf/landmark_point_2d.h
diff --git a/hello_wolf/processor_range_bearing.cpp b/demos/hello_wolf/processor_range_bearing.cpp
similarity index 100%
rename from hello_wolf/processor_range_bearing.cpp
rename to demos/hello_wolf/processor_range_bearing.cpp
diff --git a/hello_wolf/processor_range_bearing.h b/demos/hello_wolf/processor_range_bearing.h
similarity index 100%
rename from hello_wolf/processor_range_bearing.h
rename to demos/hello_wolf/processor_range_bearing.h
diff --git a/hello_wolf/sensor_range_bearing.cpp b/demos/hello_wolf/sensor_range_bearing.cpp
similarity index 100%
rename from hello_wolf/sensor_range_bearing.cpp
rename to demos/hello_wolf/sensor_range_bearing.cpp
diff --git a/hello_wolf/sensor_range_bearing.h b/demos/hello_wolf/sensor_range_bearing.h
similarity index 100%
rename from hello_wolf/sensor_range_bearing.h
rename to demos/hello_wolf/sensor_range_bearing.h
diff --git a/hello_wolf/yaml/hello_wolf_config.yaml b/demos/hello_wolf/yaml/hello_wolf_config.yaml
similarity index 69%
rename from hello_wolf/yaml/hello_wolf_config.yaml
rename to demos/hello_wolf/yaml/hello_wolf_config.yaml
index b84d7776622264f96a4597ade146d64bcec86438..1077fe00cb442147b03a36ffddba5b3b37016e8d 100644
--- a/hello_wolf/yaml/hello_wolf_config.yaml
+++ b/demos/hello_wolf/yaml/hello_wolf_config.yaml
@@ -2,6 +2,11 @@ config:
 
   problem:
   
+    tree_manager:
+      type: "TreeManagerSlidingWindow"
+      n_key_frames: -1
+      fix_first_key_frame: false
+      viral_remove_empty_parent: true
     frame_structure:      "PO"            # keyframes have position and orientation
     dimension:            2               # space is 2d
     prior:
@@ -17,7 +22,7 @@ config:
       name:               "sen odom"
       extrinsic: 
         pose:             [0,0, 0]
-      follow:             "hello_wolf/yaml/sensor_odom_2d.yaml"         # config parameters in this file
+      follow:             "demos/hello_wolf/yaml/sensor_odom_2d.yaml"         # config parameters in this file
 
     - type:               "SensorRangeBearing"
       plugin:             "core"
@@ -25,7 +30,7 @@ config:
       extrinsic:
         pose:             [1,1, 0]
       noise_range_metres_std: 0.2                                       # parser only considers first appearence so the following file parsing will not overwrite this param
-      follow:             hello_wolf/yaml/sensor_range_bearing.yaml     # config parameters in this file
+      follow:             demos/hello_wolf/yaml/sensor_range_bearing.yaml     # config parameters in this file
           
   processors:
     
@@ -33,10 +38,10 @@ config:
       plugin:             "core"
       name:               "prc odom"
       sensor_name:        "sen odom"                                    # attach processor to this sensor
-      follow:             hello_wolf/yaml/processor_odom_2d.yaml        # config parameters in this file
+      follow:             demos/hello_wolf/yaml/processor_odom_2d.yaml        # config parameters in this file
     
     - type:               "ProcessorRangeBearing"
       plugin:             "core"
       name:               "prc rb"
       sensor_name:        "sen rb"                                      # attach processor to this sensor
-      follow:             hello_wolf/yaml/processor_range_bearing.yaml  # config parameters in this file
+      follow:             demos/hello_wolf/yaml/processor_range_bearing.yaml  # config parameters in this file
diff --git a/hello_wolf/yaml/processor_odom_2d.yaml b/demos/hello_wolf/yaml/processor_odom_2d.yaml
similarity index 92%
rename from hello_wolf/yaml/processor_odom_2d.yaml
rename to demos/hello_wolf/yaml/processor_odom_2d.yaml
index bee82ff9ad905a72dc6c1ffd46ac6d7267ae8870..7e345ef211f52897b17267065e28feec0bf4b143 100644
--- a/hello_wolf/yaml/processor_odom_2d.yaml
+++ b/demos/hello_wolf/yaml/processor_odom_2d.yaml
@@ -10,3 +10,4 @@ keyframe_vote:
   angle_turned:       999
   max_buff_length:    999
   cov_det:            999
+apply_loss_function: true
diff --git a/hello_wolf/yaml/processor_range_bearing.yaml b/demos/hello_wolf/yaml/processor_range_bearing.yaml
similarity index 84%
rename from hello_wolf/yaml/processor_range_bearing.yaml
rename to demos/hello_wolf/yaml/processor_range_bearing.yaml
index 61efbf8e31ee32ab9a348133a67037c5fbbdafee..3c257678c9a73eeb3b415e976b55eeddb3a79edd 100644
--- a/hello_wolf/yaml/processor_range_bearing.yaml
+++ b/demos/hello_wolf/yaml/processor_range_bearing.yaml
@@ -5,3 +5,5 @@ time_tolerance:       0.1
 keyframe_vote:
   voting_active:      true
   voting_aux_active:  false
+
+apply_loss_function: true
diff --git a/hello_wolf/yaml/sensor_odom_2d.yaml b/demos/hello_wolf/yaml/sensor_odom_2d.yaml
similarity index 87%
rename from hello_wolf/yaml/sensor_odom_2d.yaml
rename to demos/hello_wolf/yaml/sensor_odom_2d.yaml
index 2149405a784f637087572df559287f3f36942d7c..65ac28219471ad65180538e526521d7866391a01 100644
--- a/hello_wolf/yaml/sensor_odom_2d.yaml
+++ b/demos/hello_wolf/yaml/sensor_odom_2d.yaml
@@ -2,3 +2,4 @@ type: "SensorOdom2d"              # This must match the KEY used in the FactoryS
 
 k_disp_to_disp:   0.1  # m^2   / m
 k_rot_to_rot:     0.1  # rad^2 / rad
+apply_loss_function: true
diff --git a/hello_wolf/yaml/sensor_range_bearing.yaml b/demos/hello_wolf/yaml/sensor_range_bearing.yaml
similarity index 58%
rename from hello_wolf/yaml/sensor_range_bearing.yaml
rename to demos/hello_wolf/yaml/sensor_range_bearing.yaml
index 40a2387a041f8a34a41c5669218dd4a4eb00c0bf..d1625337dfc0b0d323d662a727c1ac298117a455 100644
--- a/hello_wolf/yaml/sensor_range_bearing.yaml
+++ b/demos/hello_wolf/yaml/sensor_range_bearing.yaml
@@ -1,4 +1,5 @@
 type:                       "SensorRangeBearing"
 
 noise_range_metres_std:     0.1
-noise_bearing_degrees_std:  0.5  
+noise_bearing_degrees_std:  0.5
+apply_loss_function: true
diff --git a/include/core/common/node_base.h b/include/core/common/node_base.h
index 4488ab30ec274eeb84e49b7dcd600de9a93acf5e..2a6120408718df85ebb2945c9800d71b0060b6fd 100644
--- a/include/core/common/node_base.h
+++ b/include/core/common/node_base.h
@@ -27,8 +27,8 @@ namespace wolf {
  *    - "LANDMARK"
  *
  *  - A unique type, which is a subcategory of the above. The list here cannot be exhaustive, but a few examples follow:
- *    - "SesorCamera"
- *    - "SesorLaser2d"
+ *    - "SensorCamera"
+ *    - "SensorLaser2d"
  *    - "LandmarkPoint3d"
  *    - "ProcessorLaser2d"
  *
diff --git a/include/core/common/wolf.h b/include/core/common/wolf.h
index 93b753b77cbe1560b1eef3a50f9e299e188da2ff..ca7da8dbe679b5bf5f0b3ca8518a6cd045e0aafa 100644
--- a/include/core/common/wolf.h
+++ b/include/core/common/wolf.h
@@ -212,6 +212,10 @@ WOLF_PTR_TYPEDEFS(NodeBase);
 // Problem
 WOLF_PTR_TYPEDEFS(Problem);
 
+// Tree Manager
+WOLF_PTR_TYPEDEFS(TreeManagerBase);
+WOLF_STRUCT_PTR_TYPEDEFS(ParamsTreeManagerBase);
+
 // Hardware
 WOLF_PTR_TYPEDEFS(HardwareBase);
 
diff --git a/include/core/factor/factor_autodiff.h b/include/core/factor/factor_autodiff.h
index d5e86d2f168acce03feb9085420de1c6ad901ab8..71e09826bbc8f37b5b594e3c93d1041c7f83dcb5 100644
--- a/include/core/factor/factor_autodiff.h
+++ b/include/core/factor/factor_autodiff.h
@@ -15,7 +15,7 @@
 namespace wolf {
 
 //template class FactorAutodiff
-template <class FacT, 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>
+template <class FacT, 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, unsigned int B10 = 0, unsigned int B11 = 0>
 class FactorAutodiff : public FactorBase
 {
     public:
@@ -31,12 +31,15 @@ class FactorAutodiff : public FactorBase
         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 unsigned int block10Size = B10;
+        static const unsigned int block11Size = B11;
+        static const unsigned int n_blocks = 12;
 
         static const std::vector<unsigned int> state_block_sizes_;
 
         typedef ceres::Jet<double, B0 + B1 + B2 + B3 + B4 +
-                                   B5 + B6 + B7 + B8 + B9> WolfJet;
+                                   B5 + B6 + B7 + B8 + B9 +
+                                   B10 + B11> WolfJet;
 
     protected:
 
@@ -54,6 +57,8 @@ class FactorAutodiff : public FactorBase
         std::array<WolfJet, B7>* jets_7_;
         std::array<WolfJet, B8>* jets_8_;
         std::array<WolfJet, B9>* jets_9_;
+        std::array<WolfJet, B10>* jets_10_;
+        std::array<WolfJet, B11>* jets_11_;
 
     public:
         /** \brief Constructor valid for all categories (ABSOLUTE, FRAME, FEATURE, LANDMARK)
@@ -75,9 +80,11 @@ class FactorAutodiff : public FactorBase
                        StateBlockPtr _state6Ptr,
                        StateBlockPtr _state7Ptr,
                        StateBlockPtr _state8Ptr,
-                       StateBlockPtr _state9Ptr) :
+                       StateBlockPtr _state9Ptr,
+                       StateBlockPtr _state10Ptr,
+                       StateBlockPtr _state11Ptr) :
             FactorBase(_tp, _frame_other_ptr, _capture_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}),
+            state_ptrs_({_state0Ptr,_state1Ptr,_state2Ptr,_state3Ptr,_state4Ptr,_state5Ptr,_state6Ptr,_state7Ptr,_state8Ptr,_state9Ptr,_state10Ptr,_state11Ptr}),
             residuals_jets_(new std::array<WolfJet, RES>),
             jets_0_(new std::array<WolfJet, B0>),
             jets_1_(new std::array<WolfJet, B1>),
@@ -88,7 +95,9 @@ class FactorAutodiff : public FactorBase
             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>)
+            jets_9_(new std::array<WolfJet, B9>),
+            jets_10_(new std::array<WolfJet, B10>),
+            jets_11_(new std::array<WolfJet, B11>)
         {
             // initialize jets
             unsigned int last_jet_idx = 0;
@@ -111,7 +120,11 @@ class FactorAutodiff : public FactorBase
             for (unsigned int i = 0; i < B8; i++)
                (*jets_8_)[i] = WolfJet(0, last_jet_idx++);
             for (unsigned int i = 0; i < B9; i++)
-                (*jets_9_)[i] = WolfJet(0, last_jet_idx++);
+               (*jets_9_)[i] = WolfJet(0, last_jet_idx++);
+            for (unsigned int i = 0; i < B10; i++)
+               (*jets_10_)[i] = WolfJet(0, last_jet_idx++);
+            for (unsigned int i = 0; i < B11; i++)
+               (*jets_11_)[i] = WolfJet(0, last_jet_idx++);
         }
 
         virtual ~FactorAutodiff()
@@ -126,6 +139,8 @@ class FactorAutodiff : public FactorBase
             delete jets_7_;
             delete jets_8_;
             delete jets_9_;
+            delete jets_10_;
+            delete jets_11_;
             delete residuals_jets_;
         }
 
@@ -154,6 +169,8 @@ class FactorAutodiff : public FactorBase
                                                   parameters[7],
                                                   parameters[8],
                                                   parameters[9],
+                                                  parameters[10],
+                                                  parameters[11],
                                                   residuals);
             }
             // also compute jacobians
@@ -175,6 +192,8 @@ class FactorAutodiff : public FactorBase
                                                   jets_7_->data(),
                                                   jets_8_->data(),
                                                   jets_9_->data(),
+                                                  jets_10_->data(),
+                                                  jets_11_->data(),
                                                   residuals_jets_->data());
 
                 // fill the residual array
@@ -218,6 +237,10 @@ class FactorAutodiff : public FactorBase
                 (*jets_8_)[i].a = parameters[8][i];
             for (unsigned int i = 0; i < B9; i++)
                 (*jets_9_)[i].a = parameters[9][i];
+            for (unsigned int i = 0; i < B10; i++)
+                (*jets_10_)[i].a = parameters[10][i];
+            for (unsigned int i = 0; i < B11; i++)
+                (*jets_11_)[i].a = parameters[11][i];
         }
 
         /** \brief Returns a vector of Jacobian matrix corresponding to each state block evaluated in the point provided in _states_ptr
@@ -244,6 +267,8 @@ class FactorAutodiff : public FactorBase
                                               jets_7_->data(),
                                               jets_8_->data(),
                                               jets_9_->data(),
+                                              jets_10_->data(),
+                                              jets_11_->data(),
                                               residuals_jets_->data());
 
             // fill the residual vector
@@ -299,10 +324,552 @@ class FactorAutodiff : public FactorBase
         }
 };
 
+
+////////////////// SPECIALIZATION 11 BLOCKS ////////////////////////////////////////////////////////////////////////
+
+template <class FacT,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,unsigned int B10>
+class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,0> : public FactorBase
+{
+   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 block10Size = B10;
+       static const unsigned int block11Size = 0;
+       static const unsigned int n_blocks = 11;
+
+       static const std::vector<unsigned int> state_block_sizes_;
+
+       typedef ceres::Jet<double, B0 + B1 + B2 + B3 + B4 +
+                                  B5 + B6 + B7 + B8 + B9 + B10> 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_;
+       std::array<WolfJet, B10>* jets_10_;
+
+   public:
+
+       FactorAutodiff(const std::string&  _tp,
+                      const FrameBasePtr& _frame_other_ptr,
+                      const CaptureBasePtr& _capture_other_ptr,
+                      const FeatureBasePtr& _feature_other_ptr,
+                      const LandmarkBasePtr& _landmark_other_ptr,
+                      const ProcessorBasePtr& _processor_ptr,
+                      bool _apply_loss_function,
+                      FactorStatus _status,
+                      StateBlockPtr _state0Ptr,
+                      StateBlockPtr _state1Ptr,
+                      StateBlockPtr _state2Ptr,
+                      StateBlockPtr _state3Ptr,
+                      StateBlockPtr _state4Ptr,
+                      StateBlockPtr _state5Ptr,
+                      StateBlockPtr _state6Ptr,
+                      StateBlockPtr _state7Ptr,
+                      StateBlockPtr _state8Ptr,
+                      StateBlockPtr _state9Ptr,
+                      StateBlockPtr _state10Ptr) :
+           FactorBase(_tp, _frame_other_ptr, _capture_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,_state10Ptr}),
+           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>),
+           jets_10_(new std::array<WolfJet, B10>)
+       {
+           // initialize jets
+           unsigned int last_jet_idx = 0;
+           for (unsigned int i = 0; i < B0; i++)
+              (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B1; i++)
+              (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B2; i++)
+              (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B3; i++)
+              (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B4; i++)
+              (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B5; i++)
+              (*jets_5_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B6; i++)
+              (*jets_6_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B7; i++)
+              (*jets_7_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B8; i++)
+              (*jets_8_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B9; i++)
+              (*jets_9_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B10; i++)
+              (*jets_10_)[i] = WolfJet(0, last_jet_idx++);
+           state_ptrs_.resize(n_blocks);
+       }
+
+       virtual ~FactorAutodiff()
+       {
+           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 jets_10_;
+           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<FacT const*>(this))(parameters[0],
+                                                 parameters[1],
+                                                 parameters[2],
+                                                 parameters[3],
+                                                 parameters[4],
+                                                 parameters[5],
+                                                 parameters[6],
+                                                 parameters[7],
+                                                 parameters[8],
+                                                 parameters[9],
+                                                 parameters[10],
+                                                 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<FacT 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(),
+                                                 jets_10_->data(),
+                                                 residuals_jets_->data());
+
+               // fill the residual array
+               for (unsigned int i = 0; i < RES; i++)
+                   residuals[i] = (*residuals_jets_)[i].a;
+
+               // fill the jacobian matrices
+               for (unsigned int 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 (unsigned int i = 0; i < B0; i++)
+               (*jets_0_)[i].a = parameters[0][i];
+           for (unsigned int i = 0; i < B1; i++)
+               (*jets_1_)[i].a = parameters[1][i];
+           for (unsigned int i = 0; i < B2; i++)
+               (*jets_2_)[i].a = parameters[2][i];
+           for (unsigned int i = 0; i < B3; i++)
+               (*jets_3_)[i].a = parameters[3][i];
+           for (unsigned int i = 0; i < B4; i++)
+               (*jets_4_)[i].a = parameters[4][i];
+           for (unsigned int i = 0; i < B5; i++)
+               (*jets_5_)[i].a = parameters[5][i];
+           for (unsigned int i = 0; i < B6; i++)
+               (*jets_6_)[i].a = parameters[6][i];
+           for (unsigned int i = 0; i < B7; i++)
+               (*jets_7_)[i].a = parameters[7][i];
+           for (unsigned int i = 0; i < B8; i++)
+               (*jets_8_)[i].a = parameters[8][i];
+           for (unsigned int i = 0; i < B9; i++)
+               (*jets_9_)[i].a = parameters[9][i];
+           for (unsigned int i = 0; i < B10; i++)
+               (*jets_10_)[i].a = parameters[10][i];
+       }
+
+       virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const
+       {
+           assert(residual_.size() == RES);
+           jacobians_.clear();
+
+           assert(_states_ptr.size() == n_blocks);
+
+           // update jets real part
+           updateJetsRealPart(_states_ptr);
+
+           // call functor
+           (*static_cast<FacT 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(),
+                                             jets_10_->data(),
+                                             residuals_jets_->data());
+
+           // fill the residual vector
+           for (unsigned int i = 0; i < RES; i++)
+               residual_(i) = (*residuals_jets_)[i].a;
+
+           // fill the jacobian matrices
+           for (unsigned int i = 0; i<n_blocks; i++)
+           {
+               // Create a row major Jacobian
+               Eigen::MatrixRowXd Ji(Eigen::MatrixRowXd::Zero(RES, state_block_sizes_[i]));
+               // Fill Jacobian rows from jets
+               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),
+                                 Ji.data() + row * state_block_sizes_.at(i));
+               // add to the Jacobians vector
+               jacobians_.push_back(Ji);
+           }
+
+          // print jacobian matrices
+//           for (unsigned int i = 0; i < n_blocks; i++)
+//               std::cout << jacobians_[i] << std::endl << std::endl;
+       }
+
+       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 10 BLOCKS ////////////////////////////////////////////////////////////////////////
+
+template <class FacT,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>
+class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,0,0> : public FactorBase
+{
+   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 block10Size = 0;
+       static const unsigned int block11Size = 0;
+       static const unsigned int n_blocks = 10;
+
+       static const std::vector<unsigned int> state_block_sizes_;
+
+       typedef ceres::Jet<double, 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:
+
+       FactorAutodiff(const std::string&  _tp,
+                      const FrameBasePtr& _frame_other_ptr,
+                      const CaptureBasePtr& _capture_other_ptr,
+                      const FeatureBasePtr& _feature_other_ptr,
+                      const LandmarkBasePtr& _landmark_other_ptr,
+                      const ProcessorBasePtr& _processor_ptr,
+                      bool _apply_loss_function,
+                      FactorStatus _status,
+                      StateBlockPtr _state0Ptr,
+                      StateBlockPtr _state1Ptr,
+                      StateBlockPtr _state2Ptr,
+                      StateBlockPtr _state3Ptr,
+                      StateBlockPtr _state4Ptr,
+                      StateBlockPtr _state5Ptr,
+                      StateBlockPtr _state6Ptr,
+                      StateBlockPtr _state7Ptr,
+                      StateBlockPtr _state8Ptr,
+                      StateBlockPtr _state9Ptr) :
+           FactorBase(_tp, _frame_other_ptr, _capture_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 (unsigned int i = 0; i < B0; i++)
+              (*jets_0_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B1; i++)
+              (*jets_1_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B2; i++)
+              (*jets_2_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B3; i++)
+              (*jets_3_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B4; i++)
+              (*jets_4_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B5; i++)
+              (*jets_5_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B6; i++)
+              (*jets_6_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B7; i++)
+              (*jets_7_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B8; i++)
+              (*jets_8_)[i] = WolfJet(0, last_jet_idx++);
+           for (unsigned int i = 0; i < B9; i++)
+              (*jets_9_)[i] = WolfJet(0, last_jet_idx++);
+           state_ptrs_.resize(n_blocks);
+       }
+
+       virtual ~FactorAutodiff()
+       {
+           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;
+       }
+
+       virtual bool evaluate(double const* const* parameters, double* residuals, double** jacobians) const
+       {
+           // only residuals
+           if (jacobians == nullptr)
+           {
+               (*static_cast<FacT 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<FacT 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 (unsigned int i = 0; i < RES; i++)
+                   residuals[i] = (*residuals_jets_)[i].a;
+
+               // fill the jacobian matrices
+               for (unsigned int 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 (unsigned int i = 0; i < B0; i++)
+               (*jets_0_)[i].a = parameters[0][i];
+           for (unsigned int i = 0; i < B1; i++)
+               (*jets_1_)[i].a = parameters[1][i];
+           for (unsigned int i = 0; i < B2; i++)
+               (*jets_2_)[i].a = parameters[2][i];
+           for (unsigned int i = 0; i < B3; i++)
+               (*jets_3_)[i].a = parameters[3][i];
+           for (unsigned int i = 0; i < B4; i++)
+               (*jets_4_)[i].a = parameters[4][i];
+           for (unsigned int i = 0; i < B5; i++)
+               (*jets_5_)[i].a = parameters[5][i];
+           for (unsigned int i = 0; i < B6; i++)
+               (*jets_6_)[i].a = parameters[6][i];
+           for (unsigned int i = 0; i < B7; i++)
+               (*jets_7_)[i].a = parameters[7][i];
+           for (unsigned int i = 0; i < B8; i++)
+               (*jets_8_)[i].a = parameters[8][i];
+           for (unsigned int i = 0; i < B9; i++)
+               (*jets_9_)[i].a = parameters[9][i];
+       }
+
+       virtual void evaluate(const std::vector<const double*>& _states_ptr, Eigen::VectorXd& residual_, std::vector<Eigen::MatrixXd>& jacobians_) const
+       {
+           assert(residual_.size() == RES);
+           jacobians_.clear();
+
+           assert(_states_ptr.size() == n_blocks);
+
+           // update jets real part
+           updateJetsRealPart(_states_ptr);
+
+           // call functor
+           (*static_cast<FacT 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 (unsigned int i = 0; i < RES; i++)
+               residual_(i) = (*residuals_jets_)[i].a;
+
+           // fill the jacobian matrices
+           for (unsigned int i = 0; i<n_blocks; i++)
+           {
+               // Create a row major Jacobian
+               Eigen::MatrixRowXd Ji(Eigen::MatrixRowXd::Zero(RES, state_block_sizes_[i]));
+               // Fill Jacobian rows from jets
+               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),
+                                 Ji.data() + row * state_block_sizes_.at(i));
+               // add to the Jacobians vector
+               jacobians_.push_back(Ji);
+           }
+
+          // print jacobian matrices
+//           for (unsigned int i = 0; i < n_blocks; i++)
+//               std::cout << jacobians_[i] << std::endl << std::endl;
+       }
+
+       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 9 BLOCKS ////////////////////////////////////////////////////////////////////////
 
 template <class FacT,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 FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0> : public FactorBase
+class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0,0,0> : public FactorBase
 {
    public:
 
@@ -317,6 +884,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0> : public FactorBase
        static const unsigned int block7Size = B7;
        static const unsigned int block8Size = B8;
        static const unsigned int block9Size = 0;
+       static const unsigned int block10Size = 0;
+       static const unsigned int block11Size = 0;
        static const unsigned int n_blocks = 9;
 
        static const std::vector<unsigned int> state_block_sizes_;
@@ -554,7 +1123,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0> : public FactorBase
 ////////////////// SPECIALIZATION 8 BLOCKS ////////////////////////////////////////////////////////////////////////
 
 template <class FacT,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 FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0> : public FactorBase
+class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0,0,0> : public FactorBase
 {
    public:
 
@@ -569,6 +1138,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0> : public FactorBase
        static const unsigned int block7Size = B7;
        static const unsigned int block8Size = 0;
        static const unsigned int block9Size = 0;
+       static const unsigned int block10Size = 0;
+       static const unsigned int block11Size = 0;
        static const unsigned int n_blocks = 8;
 
        static const std::vector<unsigned int> state_block_sizes_;
@@ -795,7 +1366,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0> : public FactorBase
 ////////////////// SPECIALIZATION 7 BLOCKS ////////////////////////////////////////////////////////////////////////
 
 template <class FacT,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 FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0> : public FactorBase
+class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0,0,0> : public FactorBase
 {
    public:
 
@@ -810,6 +1381,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0> : public FactorBase
        static const unsigned int block7Size = 0;
        static const unsigned int block8Size = 0;
        static const unsigned int block9Size = 0;
+       static const unsigned int block10Size = 0;
+       static const unsigned int block11Size = 0;
        static const unsigned int n_blocks = 7;
 
        static const std::vector<unsigned int> state_block_sizes_;
@@ -1025,7 +1598,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0> : public FactorBase
 ////////////////// SPECIALIZATION 6 BLOCKS ////////////////////////////////////////////////////////////////////////
 
 template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4,unsigned int B5>
-class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0> : public FactorBase
+class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0,0,0> : public FactorBase
 {
    public:
 
@@ -1040,6 +1613,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0> : public FactorBase
        static const unsigned int block7Size = 0;
        static const unsigned int block8Size = 0;
        static const unsigned int block9Size = 0;
+       static const unsigned int block10Size = 0;
+       static const unsigned int block11Size = 0;
        static const unsigned int n_blocks = 6;
 
        static const std::vector<unsigned int> state_block_sizes_;
@@ -1240,7 +1815,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0> : public FactorBase
 ////////////////// SPECIALIZATION 5 BLOCKS ////////////////////////////////////////////////////////////////////////
 
 template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4>
-class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0> : public FactorBase
+class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0,0,0> : public FactorBase
 {
    public:
 
@@ -1255,6 +1830,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0> : public FactorBase
        static const unsigned int block7Size = 0;
        static const unsigned int block8Size = 0;
        static const unsigned int block9Size = 0;
+       static const unsigned int block10Size = 0;
+       static const unsigned int block11Size = 0;
        static const unsigned int n_blocks = 5;
 
        static const std::vector<unsigned int> state_block_sizes_;
@@ -1443,7 +2020,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0> : public FactorBase
 ////////////////// SPECIALIZATION 4 BLOCKS ////////////////////////////////////////////////////////////////////////
 
 template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3>
-class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0> : public FactorBase
+class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0,0,0> : public FactorBase
 {
    public:
 
@@ -1458,6 +2035,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0> : public FactorBase
        static const unsigned int block7Size = 0;
        static const unsigned int block8Size = 0;
        static const unsigned int block9Size = 0;
+       static const unsigned int block10Size = 0;
+       static const unsigned int block11Size = 0;
        static const unsigned int n_blocks = 4;
 
        static const std::vector<unsigned int> state_block_sizes_;
@@ -1639,7 +2218,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0> : public FactorBase
 ////////////////// SPECIALIZATION 3 BLOCKS ////////////////////////////////////////////////////////////////////////
 
 template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2>
-class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0> : public FactorBase
+class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0,0,0> : public FactorBase
 {
    public:
 
@@ -1654,6 +2233,8 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0> : public FactorBase
        static const unsigned int block7Size = 0;
        static const unsigned int block8Size = 0;
        static const unsigned int block9Size = 0;
+       static const unsigned int block10Size = 0;
+       static const unsigned int block11Size = 0;
        static const unsigned int n_blocks = 3;
 
        static const std::vector<unsigned int> state_block_sizes_;
@@ -1824,7 +2405,7 @@ class FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0> : public FactorBase
 ////////////////// SPECIALIZATION 2 BLOCKS ////////////////////////////////////////////////////////////////////////
 
 template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1>
-class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0> : public FactorBase
+class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0,0,0> : public FactorBase
 {
    public:
 
@@ -1839,6 +2420,8 @@ class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0> : public FactorBase
        static const unsigned int block7Size = 0;
        static const unsigned int block8Size = 0;
        static const unsigned int block9Size = 0;
+       static const unsigned int block10Size = 0;
+       static const unsigned int block11Size = 0;
        static const unsigned int n_blocks = 2;
 
        static const std::vector<unsigned int> state_block_sizes_;
@@ -1998,7 +2581,7 @@ class FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0> : public FactorBase
 ////////////////// SPECIALIZATION 1 BLOCK ////////////////////////////////////////////////////////////////////////
 
 template <class FacT,unsigned int RES,unsigned int B0>
-class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0> : public FactorBase
+class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0,0,0> : public FactorBase
 {
    public:
 
@@ -2013,6 +2596,8 @@ class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0> : public FactorBase
        static const unsigned int block7Size = 0;
        static const unsigned int block8Size = 0;
        static const unsigned int block9Size = 0;
+       static const unsigned int block10Size = 0;
+       static const unsigned int block11Size = 0;
        static const unsigned int n_blocks = 1;
 
        static const std::vector<unsigned int> state_block_sizes_;
@@ -2162,113 +2747,146 @@ class FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0> : public FactorBase
 //                                          STATIC CONST VECTORS INITIALIZATION
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 // state_block_sizes_
+// 12 BLOCKS
+template <class FacT,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,unsigned int B10,unsigned int B11>
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11};
+// 11 BLOCKS
+template <class FacT,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,unsigned int B10>
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10};
 // 10 BLOCKS
 template <class FacT,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> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8,B9};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8,B9};
 // 9 BLOCKS
 template <class FacT,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> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7,B8};
 // 8 BLOCKS
 template <class FacT,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> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6,B7};
 // 7 BLOCKS
 template <class FacT,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> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5,B6};
 // 6 BLOCKS
 template <class FacT,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> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4,B5};
 // 5 BLOCKS
 template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4>
-const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3,B4};
 // 4 BLOCKS
 template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3>
-const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2,B3};
 // 3 BLOCKS
 template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2>
-const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1,B2};
 // 2 BLOCKS
 template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1>
-const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0,B1};
 // 1 BLOCK
 template <class FacT,unsigned int RES,unsigned int B0>
-const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0,0,0>::state_block_sizes_ = {B0};
 
 // jacobian_locations_
+// 12 BLOCKS
+template <class FacT,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,unsigned int B10,unsigned int B11>
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11>::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,
+                                                                                                                       B0+B1+B2+B3+B4+B5+B6+B7+B8+B9,
+                                                                                                                       B0+B1+B2+B3+B4+B5+B6+B7+B8+B9+B10};
+// 10 BLOCKS
+template <class FacT,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,unsigned int B10>
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,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,
+                                                                                                                     B0+B1+B2+B3+B4+B5+B6+B7+B8,
+                                                                                                                     B0+B1+B2+B3+B4+B5+B6+B7+B8+B9};
 // 10 BLOCKS
 template <class FacT,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> FactorAutodiff<FacT,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};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,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,
+                                                                                                                   B0+B1+B2+B3+B4+B5+B6+B7,
+                                                                                                                   B0+B1+B2+B3+B4+B5+B6+B7+B8};
 // 9 BLOCKS
 template <class FacT,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> FactorAutodiff<FacT,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};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,B8,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,
+                                                                                                                  B0+B1+B2+B3+B4+B5+B6,
+                                                                                                                  B0+B1+B2+B3+B4+B5+B6+B7};
 // 8 BLOCKS
 template <class FacT,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> FactorAutodiff<FacT,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};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,B7,0,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,
+                                                                                                                 B0+B1+B2+B3+B4+B5+B6};
 // 7 BLOCKS
 template <class FacT,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> FactorAutodiff<FacT,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};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,B6,0,0,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 FacT,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> FactorAutodiff<FacT,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};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,B5,0,0,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 FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3,unsigned int B4>
-const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0>::jacobian_locations_ = {0,
-                                                                                                          B0,
-                                                                                                          B0+B1,
-                                                                                                          B0+B1+B2,
-                                                                                                          B0+B1+B2+B3};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,B4,0,0,0,0,0,0,0>::jacobian_locations_ = {0,
+                                                                                                              B0,
+                                                                                                              B0+B1,
+                                                                                                              B0+B1+B2,
+                                                                                                              B0+B1+B2+B3};
 // 4 BLOCKS
 template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2,unsigned int B3>
-const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0>::jacobian_locations_ = {0,
-                                                                                                         B0,
-                                                                                                         B0+B1,
-                                                                                                         B0+B1+B2};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,B3,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0,
+                                                                                                             B0,
+                                                                                                             B0+B1,
+                                                                                                             B0+B1+B2};
 // 3 BLOCKS
 template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1,unsigned int B2>
-const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0>::jacobian_locations_ = {0,
-                                                                                                        B0,
-                                                                                                        B0+B1};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,B2,0,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0,
+                                                                                                            B0,
+                                                                                                            B0+B1};
 // 2 BLOCKS
 template <class FacT,unsigned int RES,unsigned int B0,unsigned int B1>
-const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0,
-                                                                                                       B0};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,B1,0,0,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0,
+                                                                                                           B0};
 // 1 BLOCK
 template <class FacT,unsigned int RES,unsigned int B0>
-const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0};
+const std::vector<unsigned int> FactorAutodiff<FacT,RES,B0,0,0,0,0,0,0,0,0,0,0,0>::jacobian_locations_ = {0};
 
 } // namespace wolf
 
diff --git a/include/core/factor/factor_autodiff_distance_3d.h b/include/core/factor/factor_autodiff_distance_3d.h
index 8dc182d6f92ec60d7ba310ed1e7f94e27a9281fc..1ef90ba493d3d3922685f7f42ff2b14402d7a546 100644
--- a/include/core/factor/factor_autodiff_distance_3d.h
+++ b/include/core/factor/factor_autodiff_distance_3d.h
@@ -23,7 +23,7 @@ class FactorAutodiffDistance3d : public FactorAutodiff<FactorAutodiffDistance3d,
                                  const ProcessorBasePtr& _processor_ptr,
                                  bool                    _apply_loss_function,
                                  FactorStatus            _status) :
-            FactorAutodiff("DISTANCE 3d",
+            FactorAutodiff("FactorAutodiffDistance3d",
                             _frm_other,
                             nullptr,
                             nullptr,
diff --git a/include/core/factor/factor_diff_drive.h b/include/core/factor/factor_diff_drive.h
index d936a99d6c1d64f29fda2c5aeca1806e0065c4d1..7b189e4424b419b655833020ff9a94c71952748e 100644
--- a/include/core/factor/factor_diff_drive.h
+++ b/include/core/factor/factor_diff_drive.h
@@ -14,6 +14,7 @@
 #include "core/factor/factor_autodiff.h"
 #include "core/frame/frame_base.h"
 #include "core/feature/feature_motion.h"
+#include "core/math/rotations.h"
 
 namespace
 {
@@ -126,10 +127,7 @@ inline bool FactorDiffDrive::operator ()(const T* const _p1, const T* const _o1,
     residuals = delta_corrected - delta_predicted;
 
     // angle remapping
-    while (residuals(2) > T(M_PI))
-        residuals(2) = residuals(2) - T(2. * M_PI);
-    while (residuals(2) <= T(-M_PI))
-        residuals(2) = residuals(2) + T(2. * M_PI);
+    pi2pi(residuals(2));
 
     // weighted residual
     residuals = getMeasurementSquareRootInformationUpper() * residuals;
diff --git a/include/core/factor/factor_odom_2d.h b/include/core/factor/factor_odom_2d.h
index e20f0f50f158b7ed04e2d09054fafee9300a6f29..1ce2a375c131cea5234a5e603cdf2808764bc4cc 100644
--- a/include/core/factor/factor_odom_2d.h
+++ b/include/core/factor/factor_odom_2d.h
@@ -4,6 +4,7 @@
 //Wolf includes
 #include "core/factor/factor_autodiff.h"
 #include "core/frame/frame_base.h"
+#include "core/math/rotations.h"
 
 //#include "ceres/jet.h"
 
@@ -72,10 +73,7 @@ inline bool FactorOdom2d::operator ()(const T* const _p1, const T* const _o1, co
 
     // Error
     er = expected_measurement - getMeasurement();
-    while (er(2) > T( M_PI ))
-        er(2) -=   T( 2 * M_PI );
-    while (er(2) < T( -M_PI ))
-        er(2) +=   T( 2 * M_PI );
+    er(2) = pi2pi(er(2));
 
     // Residuals
     res = getMeasurementSquareRootInformationUpper() * er;
diff --git a/include/core/factor/factor_odom_2d_analytic.h b/include/core/factor/factor_odom_2d_analytic.h
index c7eec32a1778b9f1ad69da6c3c0087e50509a904..52ea04ccd817f2a6c914d771737c284bca4ce664 100644
--- a/include/core/factor/factor_odom_2d_analytic.h
+++ b/include/core/factor/factor_odom_2d_analytic.h
@@ -18,7 +18,7 @@ class FactorOdom2dAnalytic : public FactorRelative2dAnalytic
                              const ProcessorBasePtr& _processor_ptr,
                              bool _apply_loss_function,
                              FactorStatus _status = FAC_ACTIVE) :
-            FactorRelative2dAnalytic("ODOM_2d",
+            FactorRelative2dAnalytic("FactorOdom2dAnalytic",
                                      _ftr_ptr,
                                      _frame_ptr,
                                      _processor_ptr,
diff --git a/include/core/factor/factor_odom_2d_closeloop.h b/include/core/factor/factor_odom_2d_closeloop.h
index e7d35aefa48b549174d060668cbee540edb6e9e2..85a1785440a03a15a899117b619d3d07aaa3eb39 100644
--- a/include/core/factor/factor_odom_2d_closeloop.h
+++ b/include/core/factor/factor_odom_2d_closeloop.h
@@ -4,6 +4,7 @@
 //Wolf includes
 #include "core/factor/factor_autodiff.h"
 #include "core/frame/frame_base.h"
+#include "core/math/rotations.h"
 
 //#include "ceres/jet.h"
 
@@ -71,10 +72,7 @@ inline bool FactorOdom2dCloseloop::operator ()(const T* const _p1, const T* cons
 
     // Error
     er = expected_measurement - getMeasurement().cast<T>();
-    while (er(2) > T( M_PI ))
-        er(2) -=   T( 2 * M_PI );
-    while (er(2) < T( -M_PI ))
-        er(2) +=   T( 2 * M_PI );
+    er(2)=pi2pi(er(2));
 
     // Residuals
     res = getMeasurementSquareRootInformationUpper().cast<T>() * er;
diff --git a/include/core/factor/factor_pose_2d.h b/include/core/factor/factor_pose_2d.h
index ce63c806017117e67d18c2e79c34468e6b16a61c..f11b674e7775c78c0f0f306be69c85c832e328de 100644
--- a/include/core/factor/factor_pose_2d.h
+++ b/include/core/factor/factor_pose_2d.h
@@ -54,11 +54,7 @@ inline bool FactorPose2d::operator ()(const T* const _p, const T* const _o, T* _
     Eigen::Matrix<T,3,1> er;
     er(0) = meas(0) - _p[0];
     er(1) = meas(1) - _p[1];
-    er(2) = meas(2) - _o[0];
-    while (er[2] > T(M_PI))
-        er(2) = er(2) - T(2*M_PI);
-    while (er(2) <= T(-M_PI))
-        er(2) = er(2) + T(2*M_PI);
+    er(2) = pi2pi(meas(2) - _o[0]);
 
     // residual
     Eigen::Map<Eigen::Matrix<T,3,1>> res(_residuals);
diff --git a/include/core/factor/factor_quaternion_absolute.h b/include/core/factor/factor_quaternion_absolute.h
index 6533bd414d54a9eb45da8c92336ba3d1f0e07739..402615a5e5c4f11d1f306d57119cb7668031c459 100644
--- a/include/core/factor/factor_quaternion_absolute.h
+++ b/include/core/factor/factor_quaternion_absolute.h
@@ -27,7 +27,7 @@ class FactorQuaternionAbsolute: public FactorAutodiff<FactorQuaternionAbsolute,3
                                  ProcessorBasePtr _processor_ptr = nullptr,
                                  bool _apply_loss_function = false,
                                  FactorStatus _status = FAC_ACTIVE) :
-            FactorAutodiff<FactorQuaternionAbsolute,3,4>("QUATERNION ABS",
+            FactorAutodiff<FactorQuaternionAbsolute,3,4>("FactorQuaternionAbsolute",
                                                          nullptr,
                                                          nullptr,
                                                          nullptr,
diff --git a/include/core/factor/factor_relative_2d_analytic.h b/include/core/factor/factor_relative_2d_analytic.h
index 5a67da1ff6c0e17614902ebc3195dd8124ec0ed6..2dba90bc6d4ead00634f601bf232d4471860c418 100644
--- a/include/core/factor/factor_relative_2d_analytic.h
+++ b/include/core/factor/factor_relative_2d_analytic.h
@@ -4,6 +4,7 @@
 //Wolf includes
 #include "core/factor/factor_analytic.h"
 #include "core/landmark/landmark_base.h"
+#include "core/math/rotations.h"
 #include <Eigen/StdVector>
 
 namespace wolf {
@@ -19,11 +20,11 @@ class FactorRelative2dAnalytic : public FactorAnalytic
          **/
         FactorRelative2dAnalytic(const std::string& _tp,
                                      const FeatureBasePtr& _ftr_ptr,
-                                     const FrameBasePtr& _frame_ptr,
+                                     const FrameBasePtr& _frame_other_ptr,
                                      const ProcessorBasePtr& _processor_ptr,
                                      bool _apply_loss_function,
                                      FactorStatus _status = FAC_ACTIVE) :
-            FactorAnalytic(_tp, _frame_ptr, nullptr, nullptr, nullptr, _processor_ptr, _apply_loss_function, _status, _frame_ptr->getP(), _frame_ptr->getO(), _ftr_ptr->getFrame()->getP(), _ftr_ptr->getFrame()->getO())
+            FactorAnalytic(_tp, _frame_other_ptr, nullptr, nullptr, nullptr, _processor_ptr, _apply_loss_function, _status, _frame_other_ptr->getP(), _frame_other_ptr->getO(), _ftr_ptr->getFrame()->getP(), _ftr_ptr->getFrame()->getO())
         {
             //
         }
@@ -45,11 +46,11 @@ class FactorRelative2dAnalytic : public FactorAnalytic
          **/
         FactorRelative2dAnalytic(const std::string& _tp,
                                      const FeatureBasePtr& _ftr_ptr,
-                                     const LandmarkBasePtr& _landmark_ptr,
+                                     const LandmarkBasePtr& _landmark_other_ptr,
                                      const ProcessorBasePtr& _processor_ptr,
                                      bool _apply_loss_function,
                                      FactorStatus _status = FAC_ACTIVE) :
-            FactorAnalytic(_tp, nullptr, nullptr, nullptr, _landmark_ptr, _processor_ptr, _apply_loss_function, _status, _ftr_ptr->getFrame()->getP(), _ftr_ptr->getFrame()->getO(), _landmark_ptr->getP(), _landmark_ptr->getO())
+            FactorAnalytic(_tp, nullptr, nullptr, nullptr, _landmark_other_ptr, _processor_ptr, _apply_loss_function, _status, _ftr_ptr->getFrame()->getP(), _ftr_ptr->getFrame()->getO(), _landmark_other_ptr->getP(), _landmark_other_ptr->getO())
         {
             //
         }
@@ -113,10 +114,7 @@ inline Eigen::VectorXd FactorRelative2dAnalytic::evaluateResiduals(
     expected_measurement(2) = _st_vector[3](0) - _st_vector[1](0);
     // Residual
     residual = expected_measurement - getMeasurement();
-    while (residual(2) > M_PI)
-        residual(2) = residual(2) - 2 * M_PI;
-    while (residual(2) <= -M_PI)
-        residual(2) = residual(2) + 2 * M_PI;
+    residual(2) = pi2pi(residual(2));
     residual = getMeasurementSquareRootInformationUpper() * residual;
     return residual;
 }
diff --git a/include/core/factor/factor_relative_pose_2d_with_extrinsics.h b/include/core/factor/factor_relative_pose_2d_with_extrinsics.h
new file mode 100644
index 0000000000000000000000000000000000000000..be13135c9c7e3e0899ac2bb9043f4dd1b7b60ef2
--- /dev/null
+++ b/include/core/factor/factor_relative_pose_2d_with_extrinsics.h
@@ -0,0 +1,119 @@
+#ifndef FACTOR_RELATIVE_POSE_2D_WITH_EXTRINSICS_THETA_H_
+#define FACTOR_RELATIVE_POSE_2D_WITH_EXTRINSICS_THETA_H_
+
+//Wolf includes
+#include "core/factor/factor_autodiff.h"
+#include "core/frame/frame_base.h"
+#include "core/math/rotations.h"
+
+//#include "ceres/jet.h"
+
+namespace wolf {
+
+WOLF_PTR_TYPEDEFS(FactorRelativePose2dWithExtrinsics);
+
+//class
+class FactorRelativePose2dWithExtrinsics : public FactorAutodiff<FactorRelativePose2dWithExtrinsics, 3, 2, 1, 2, 1, 2, 1>
+{
+    public:
+        FactorRelativePose2dWithExtrinsics(const FeatureBasePtr& _ftr_ptr,
+                                           const FrameBasePtr& _frame_other_ptr,
+                                           const ProcessorBasePtr& _processor_ptr,
+                                           bool _apply_loss_function,
+                                           FactorStatus _status = FAC_ACTIVE) :
+             FactorAutodiff<FactorRelativePose2dWithExtrinsics, 3, 2, 1, 2, 1, 2, 1>("FactorRelativePose2dWithExtrinsics",
+                                                                                     _frame_other_ptr, nullptr, nullptr, nullptr,
+                                                                                     _processor_ptr,
+                                                                                     _apply_loss_function,
+                                                                                     _status,
+                                                                                     _frame_other_ptr->getP(),
+                                                                                     _frame_other_ptr->getO(),
+                                                                                     _ftr_ptr->getFrame()->getP(),
+                                                                                     _ftr_ptr->getFrame()->getO(),
+                                                                                     _ftr_ptr->getCapture()->getSensorP(),
+                                                                                     _ftr_ptr->getCapture()->getSensorO())
+        {
+            assert(_ftr_ptr->getCapture()->getSensorP() != nullptr && "No extrinsics found!");
+            assert(_ftr_ptr->getCapture()->getSensorO() != nullptr && "No extrinsics found!");
+            //
+        }
+
+        virtual ~FactorRelativePose2dWithExtrinsics() = default;
+
+        virtual std::string getTopology() const override
+        {
+            return std::string("MOTION");
+        }
+
+        template<typename T>
+        bool operator ()(const T* const _p1, const T* const _o1, const T* const _p2, const T* const _o2, const T* const _sp, const T* const _so,
+                         T* _residuals) const;
+};
+
+template<typename T>
+inline bool FactorRelativePose2dWithExtrinsics::operator ()(const T* const _p1, const T* const _o1, const T* const _p2,
+                                          const T* const _o2, const T* const _ps, const T* const _os, T* _residuals) const
+{
+
+    // MAPS
+    Eigen::Map<Eigen::Matrix<T,3,1> > res(_residuals);
+    Eigen::Map<const Eigen::Matrix<T,2,1> > p1(_p1);
+    Eigen::Map<const Eigen::Matrix<T,2,1> > p2(_p2);
+    Eigen::Map<const Eigen::Matrix<T,2,1> > ps(_ps);
+    T o1 = _o1[0];
+    T o2 = _o2[0];
+    T os = _os[0];
+
+    Eigen::Matrix<T, 3, 1> expected_measurement;
+    Eigen::Matrix<T, 3, 1> er; // error
+
+    // Expected measurement
+    // r1_p_r1_s1 = ps
+    // r2_p_r2_s2 = ps
+    // r1_R_s1 = R(os)
+    // r2_R_s2 = R(os)
+    // w_R_r1 = R(o1)
+    // w_R_r2 = R(o2)
+    // ----------------------------------------
+
+    // s1_p_s1_s2 = s1_R_r1*r1_p_s1_r1 +
+    //              s1_R_r1*r1_R_w*w_p_r1_w +
+    //              s1_R_r1*r1_R_w*w_p_w_r2 +
+    //              s1_R_r1*r1_R_w*w_R_r2*r2_p_r2_s2
+
+    // s1_p_s1_s2 = s1_R_r1*(r1_p_s1_r1 + r1_R_w*(w_p_r1_w + w_p_w_r2 + w_R_r2*r2_p_r2_s2))
+
+    expected_measurement.head(2) = Eigen::Rotation2D<T>(-os)*(-ps + Eigen::Rotation2D<T>(-o1)*(-p1 + p2 + Eigen::Rotation2D<T>(o2)*ps));
+    expected_measurement(2) = o2 - o1;
+
+    // Error
+    er = expected_measurement - getMeasurement().cast<T>();
+    er(2) = pi2pi(er(2));
+
+    // Residuals
+    res = getMeasurementSquareRootInformationUpper().cast<T>() * er;
+
+    ////////////////////////////////////////////////////////
+    // print Jacobian. Uncomment this as you wish (remember to uncomment #include "ceres/jet.h" above):
+//    using ceres::Jet;
+//    Eigen::MatrixXs J(3,6);
+//    J.row(0) = ((Jet<Scalar, 6>)(er(0))).v;
+//    J.row(1) = ((Jet<Scalar, 6>)(er(1))).v;
+//    J.row(2) = ((Jet<Scalar, 6>)(er(2))).v;
+//    J.row(0) = ((Jet<Scalar, 6>)(res(0))).v;
+//    J.row(1) = ((Jet<Scalar, 6>)(res(1))).v;
+//    J.row(2) = ((Jet<Scalar, 6>)(res(2))).v;
+//    if (sizeof(er(0)) != sizeof(double))
+//    {
+//        std::cout << "FactorRelativePose2dWithExtrinsics::Jacobian(c" << id() << ") = \n " << J << std::endl;
+//        std::cout << "FactorRelativePose2dWithExtrinsics::Weighted Jacobian(c" << id() << ") = \n " << J << std::endl;
+//        std::cout << "FactorRelativePose2dWithExtrinsics::Sqrt Info(c" << id() << ") = \n" << getMeasurementSquareRootInformationUpper() << std::endl;
+//    }
+    ////////////////////////////////////////////////////////
+
+    return true;
+}
+
+} // namespace wolf
+
+#endif
diff --git a/include/core/math/rotations.h b/include/core/math/rotations.h
index 7c2ede927a796adfd35e7dd9240e0128f1192c11..a0a86c6ee4c3ef095725a2df2230c2fdb8de751f 100644
--- a/include/core/math/rotations.h
+++ b/include/core/math/rotations.h
@@ -27,7 +27,7 @@ pi2pi(const T _angle)
     T angle = _angle;
     while (angle > T( M_PI ))
         angle -=   T( 2 * M_PI );
-    while (angle < T( -M_PI ))
+    while (angle <= T( -M_PI ))
         angle +=   T( 2 * M_PI );
 
     return angle;
diff --git a/include/core/problem/problem.h b/include/core/problem/problem.h
index dc485c52754078c53751c537fcfe72c674f645e0..3da679fe15b63d7a11c011e85855ea06ef564fdf 100644
--- a/include/core/problem/problem.h
+++ b/include/core/problem/problem.h
@@ -43,6 +43,7 @@ class Problem : public std::enable_shared_from_this<Problem>
     friend ProcessorMotion;
 
     protected:
+        TreeManagerBasePtr tree_manager_;
         HardwareBasePtr     hardware_ptr_;
         TrajectoryBasePtr   trajectory_ptr_;
         MapBasePtr          map_ptr_;
@@ -73,6 +74,10 @@ class Problem : public std::enable_shared_from_this<Problem>
         SizeEigen getDim() const;
         std::string getFrameStructure() const;
 
+        // Tree manager --------------------------------------
+        void setTreeManager(TreeManagerBasePtr _gm);
+        TreeManagerBasePtr getTreeManager() const;
+
         // Hardware branch ------------------------------------
         HardwareBasePtr getHardware() const;
 
@@ -361,6 +366,11 @@ class Problem : public std::enable_shared_from_this<Problem>
 namespace wolf
 {
 
+inline TreeManagerBasePtr Problem::getTreeManager() const
+{
+    return tree_manager_;
+}
+
 inline bool Problem::priorIsSet() const
 {
     return prior_is_set_;
diff --git a/include/core/processor/processor_tracker.h b/include/core/processor/processor_tracker.h
index f07d906bab503f097330a1d5203f34347a2a6c4e..efe8ef33837df852499491c5f524bcfed0765129 100644
--- a/include/core/processor/processor_tracker.h
+++ b/include/core/processor/processor_tracker.h
@@ -103,6 +103,7 @@ class ProcessorTracker : public ProcessorBase
         CaptureBasePtr incoming_ptr_;           ///< Pointer to the incoming capture being processed.
         FeatureBasePtrList new_features_last_;     ///< List of new features in \b last for landmark initialization and new key-frame creation.
         FeatureBasePtrList new_features_incoming_; ///< list of the new features of \b last successfully tracked in \b incoming
+        FeatureBasePtrList known_features_last_; ///< list of the known features in previous captures successfully tracked in \b last
         FeatureBasePtrList known_features_incoming_; ///< list of the known features in \b last successfully tracked in \b incoming
         int _dim;
 
diff --git a/include/core/processor/processor_tracker_feature.h b/include/core/processor/processor_tracker_feature.h
index 54c4168e88e33e35d6c854a5053982087a2dfaec..b16f2b6c18c03084f1808c2a6a2df275e98fd60b 100644
--- a/include/core/processor/processor_tracker_feature.h
+++ b/include/core/processor/processor_tracker_feature.h
@@ -150,8 +150,8 @@ class ProcessorTrackerFeature : public ProcessorTracker
         virtual bool voteForKeyFrame() const = 0;
 
         // We overload the advance and reset functions to update the lists of matches
-        void advanceDerived();
-        void resetDerived();
+        virtual void advanceDerived() override;
+        virtual void resetDerived() override;
 
         /**\brief Process new Features
          *
diff --git a/include/core/tree_manager/factory_tree_manager.h b/include/core/tree_manager/factory_tree_manager.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b421461c4c636a5a87ccc35b87fc83213d5b4d0
--- /dev/null
+++ b/include/core/tree_manager/factory_tree_manager.h
@@ -0,0 +1,61 @@
+#ifndef FACTORY_TREE_MANAGER_H_
+#define FACTORY_TREE_MANAGER_H_
+
+namespace wolf
+{
+class TreeManagerBase;
+struct ParamsTreeManagerBase;
+}
+
+// wolf
+#include "core/common/factory.h"
+
+// std
+
+namespace wolf
+{
+/** \brief TreeManager factory class
+ * TODO
+ */
+
+// ParamsTreeManager factory
+struct ParamsTreeManagerBase;
+typedef Factory<ParamsTreeManagerBase,
+        const std::string&> FactoryParamsTreeManager;
+template<>
+inline std::string FactoryParamsTreeManager::getClass()
+{
+    return "FactoryParamsTreeManager";
+}
+
+// TreeManager factory
+typedef Factory<TreeManagerBase,
+        const std::string&,
+        const ParamsTreeManagerBasePtr> FactoryTreeManager;
+template<>
+inline std::string FactoryTreeManager::getClass()
+{
+  return "FactoryTreeManager";
+}
+
+#define WOLF_REGISTER_TREE_MANAGER(TreeManagerType, TreeManagerName)                                   \
+  namespace{ const bool WOLF_UNUSED TreeManagerName##Registered =                                 \
+    wolf::FactoryTreeManager::get().registerCreator(TreeManagerType, TreeManagerName::create); }      \
+
+typedef Factory<TreeManagerBase,
+        const std::string&,
+        const ParamsServer&> AutoConfFactoryTreeManager;
+template<>
+inline std::string AutoConfFactoryTreeManager::getClass()
+{
+    return "AutoConfFactoryTreeManager";
+}
+
+
+#define WOLF_REGISTER_TREE_MANAGER_AUTO(TreeManagerType, TreeManagerName)                                  \
+  namespace{ const bool WOLF_UNUSED TreeManagerName##AutoConfRegistered =                             \
+    wolf::AutoConfFactoryTreeManager::get().registerCreator(TreeManagerType, TreeManagerName::create); }  \
+
+} /* namespace wolf */
+
+#endif /* FACTORY_TREE_MANAGER_H_ */
diff --git a/include/core/tree_manager/tree_manager_base.h b/include/core/tree_manager/tree_manager_base.h
new file mode 100644
index 0000000000000000000000000000000000000000..53ef9825ab029933b8c58e497e792d4f101c0406
--- /dev/null
+++ b/include/core/tree_manager/tree_manager_base.h
@@ -0,0 +1,82 @@
+#ifndef INCLUDE_TREE_MANAGER_BASE_H_
+#define INCLUDE_TREE_MANAGER_BASE_H_
+
+// Wolf includes
+#include "core/common/wolf.h"
+#include "core/common/node_base.h"
+#include "core/common/params_base.h"
+#include "core/problem/problem.h"
+
+namespace wolf
+{
+/*
+ * Macro for defining Autoconf tree manager creator for WOLF's high level API.
+ *
+ * Place a call to this macro inside your class declaration (in the tree_manager_class.h file),
+ * preferably just after the constructors.
+ *
+ * In order to use this macro, the derived processor class, ProcessorClass,
+ * must have a constructor available with the API:
+ *
+ *   TreeManagerClass(const ParamsTreeManagerPtr _params);
+ */
+#define WOLF_TREE_MANAGER_CREATE(TreeManagerClass, ParamsTreeManagerClass)                  \
+static TreeManagerBasePtr create(const std::string& _unique_name,                           \
+                                  const ParamsServer& _server)                              \
+{                                                                                           \
+    auto params         = std::make_shared<ParamsTreeManagerClass>(_unique_name, _server);  \
+                                                                                            \
+    auto tree_manager  = std::make_shared<TreeManagerClass>(params);                        \
+                                                                                            \
+    tree_manager       ->setName(_unique_name);                                             \
+                                                                                            \
+    return tree_manager;                                                                    \
+}                                                                                           \
+static TreeManagerBasePtr create(const std::string& _unique_name,                           \
+                                  const ParamsTreeManagerBasePtr _params)                   \
+{                                                                                           \
+    auto params         = std::static_pointer_cast<ParamsTreeManagerClass>(_params);        \
+                                                                                            \
+    auto tree_manager  = std::make_shared<TreeManagerClass>(params);                        \
+                                                                                            \
+    tree_manager       ->setName(_unique_name);                                             \
+                                                                                            \
+    return tree_manager;                                                                    \
+}                                                                                           \
+
+struct ParamsTreeManagerBase : public ParamsBase
+{
+    std::string prefix = "problem/tree_manager";
+    ParamsTreeManagerBase() = default;
+    ParamsTreeManagerBase(std::string _unique_name, const ParamsServer& _server):
+        ParamsBase(_unique_name, _server)
+    {
+    }
+
+    virtual ~ParamsTreeManagerBase() = default;
+
+    std::string print() const
+    {
+        return ParamsBase::print() + "\n";
+    }
+};
+
+class TreeManagerBase : public NodeBase
+{
+    public:
+        TreeManagerBase(const std::string& _type, ParamsTreeManagerBasePtr _params) :
+            NodeBase("TREE_MANAGER", _type),
+            params_(_params)
+        {}
+
+        virtual ~TreeManagerBase(){}
+
+        virtual void keyFrameCallback(FrameBasePtr _key_frame) = 0;
+
+    protected:
+        ParamsTreeManagerBasePtr params_;
+};
+
+} /* namespace wolf */
+
+#endif /* INCLUDE_TREE_MANAGER_BASE_H_ */
diff --git a/include/core/tree_manager/tree_manager_sliding_window.h b/include/core/tree_manager/tree_manager_sliding_window.h
new file mode 100644
index 0000000000000000000000000000000000000000..8b2deec3b4fe8de046e1dd6c65c646be1a773727
--- /dev/null
+++ b/include/core/tree_manager/tree_manager_sliding_window.h
@@ -0,0 +1,54 @@
+#ifndef INCLUDE_TREE_MANAGER_SLIDING_WINDOW_H_
+#define INCLUDE_TREE_MANAGER_SLIDING_WINDOW_H_
+
+#include "../tree_manager/tree_manager_base.h"
+
+namespace wolf
+{
+
+WOLF_STRUCT_PTR_TYPEDEFS(ParamsTreeManagerSlidingWindow)
+WOLF_PTR_TYPEDEFS(TreeManagerSlidingWindow)
+
+struct ParamsTreeManagerSlidingWindow : public ParamsTreeManagerBase
+{
+        ParamsTreeManagerSlidingWindow() = default;
+        ParamsTreeManagerSlidingWindow(std::string _unique_name, const wolf::ParamsServer & _server) :
+            ParamsTreeManagerBase(_unique_name, _server)
+        {
+            n_key_frames                = _server.getParam<unsigned int>(prefix + "/n_key_frames");
+            fix_first_key_frame         = _server.getParam<bool>        (prefix + "/fix_first_key_frame");
+            viral_remove_empty_parent   = _server.getParam<bool>        (prefix + "/viral_remove_empty_parent");
+        }
+        std::string print() const
+        {
+            return "\n" + ParamsTreeManagerBase::print()                                            + "\n"
+                        + "n_key_frames: "              + std::to_string(n_key_frames)              + "\n"
+                        + "fix_first_key_frame: "       + std::to_string(fix_first_key_frame)       + "\n"
+                        + "viral_remove_empty_parent: " + std::to_string(viral_remove_empty_parent) + "\n";
+        }
+
+        unsigned int n_key_frames;
+        bool fix_first_key_frame;
+        bool viral_remove_empty_parent;
+};
+
+class TreeManagerSlidingWindow : public TreeManagerBase
+{
+    public:
+        TreeManagerSlidingWindow(ParamsTreeManagerSlidingWindowPtr _params) :
+            TreeManagerBase("TreeManagerSlidingWindow", _params),
+            params_sw_(_params)
+        {};
+        WOLF_TREE_MANAGER_CREATE(TreeManagerSlidingWindow, ParamsTreeManagerSlidingWindow)
+
+        virtual ~TreeManagerSlidingWindow(){}
+
+        virtual void keyFrameCallback(FrameBasePtr _key_frame) override;
+
+    protected:
+        ParamsTreeManagerSlidingWindowPtr params_sw_;
+};
+
+} /* namespace wolf */
+
+#endif /* INCLUDE_TREE_MANAGER_SLIDING_WINDOW_H_ */
diff --git a/src/frame/frame_base.cpp b/src/frame/frame_base.cpp
index c0f4d310e1062c9a68ea94a0ee0b70f912cd9d15..217bfb8d4232a40af88670fac91a52b161377d32 100644
--- a/src/frame/frame_base.cpp
+++ b/src/frame/frame_base.cpp
@@ -12,7 +12,7 @@ namespace wolf {
 unsigned int FrameBase::frame_id_count_ = 0;
 
 FrameBase::FrameBase(const TimeStamp& _ts, StateBlockPtr _p_ptr, StateBlockPtr _o_ptr, StateBlockPtr _v_ptr) :
-            NodeBase("FRAME", "Base"),
+            NodeBase("FRAME", "FrameBase"),
             HasStateBlocks(""),
             trajectory_ptr_(),
             frame_id_(++frame_id_count_),
@@ -34,7 +34,7 @@ FrameBase::FrameBase(const TimeStamp& _ts, StateBlockPtr _p_ptr, StateBlockPtr _
 }
 
 FrameBase::FrameBase(const FrameType & _tp, const TimeStamp& _ts, StateBlockPtr _p_ptr, StateBlockPtr _o_ptr, StateBlockPtr _v_ptr) :
-            NodeBase("FRAME", "Base"),
+            NodeBase("FRAME", "FrameBase"),
             HasStateBlocks(""),
             trajectory_ptr_(),
             frame_id_(++frame_id_count_),
@@ -56,7 +56,7 @@ FrameBase::FrameBase(const FrameType & _tp, const TimeStamp& _ts, StateBlockPtr
 }
 
 FrameBase::FrameBase(const std::string _frame_structure, const SizeEigen _dim, const FrameType & _tp, const TimeStamp& _ts, const Eigen::VectorXd& _x) :
-           NodeBase("FRAME", "Base"),
+           NodeBase("FRAME", "FrameBase"),
            HasStateBlocks(_frame_structure),
            trajectory_ptr_(),
            frame_id_(++frame_id_count_),
diff --git a/src/hardware/hardware_base.cpp b/src/hardware/hardware_base.cpp
index adda7984748ebfb2fa6e40517f0d1bedc331efd2..8995fc7830b1b540c055ee1bc6aa4ca2c01c33ed 100644
--- a/src/hardware/hardware_base.cpp
+++ b/src/hardware/hardware_base.cpp
@@ -4,7 +4,7 @@
 namespace wolf {
 
 HardwareBase::HardwareBase() :
-        NodeBase("HARDWARE", "Base")
+        NodeBase("HARDWARE", "HardwareBase")
 {
 //    std::cout << "constructed H" << std::endl;
 }
diff --git a/src/problem/problem.cpp b/src/problem/problem.cpp
index 785d95f2f66293ea72202103852733da111b7365..2b605444d58ec497c044f5910af4174f31d7a06c 100644
--- a/src/problem/problem.cpp
+++ b/src/problem/problem.cpp
@@ -11,12 +11,13 @@
 #include "core/sensor/factory_sensor.h"
 #include "core/processor/factory_processor.h"
 #include "core/state_block/state_block.h"
+#include "core/tree_manager/factory_tree_manager.h"
+#include "core/tree_manager/tree_manager_base.h"
 #include "core/utils/logging.h"
 #include "core/utils/params_server.h"
 #include "core/utils/loader.h"
 #include "core/utils/check_log.h"
 
-
 // IRI libs includes
 
 // C++ includes
@@ -28,10 +29,12 @@
 #include <vector>
 #include <unordered_set>
 
+
 namespace wolf
 {
 
 Problem::Problem(const std::string& _frame_structure, SizeEigen _dim) :
+        tree_manager_(nullptr),
         hardware_ptr_(std::make_shared<HardwareBase>()),
         trajectory_ptr_(std::make_shared<TrajectoryBase>(_frame_structure)),
         map_ptr_(std::make_shared<MapBase>()),
@@ -152,6 +155,12 @@ ProblemPtr Problem::autoSetup(ParamsServer &_server)
         procesorMap.insert(std::pair<std::string, ProcessorBasePtr>(prc["name"], problem->installProcessor(prc["type"], prc["name"], prc["sensor_name"], _server)));
     }
 
+    // Tree manager
+    std::string tree_manager_type = _server.getParam<std::string>("problem/tree_manager/type");
+    WOLF_TRACE("Tree Manager Type: ", tree_manager_type);
+    if (tree_manager_type != "None" and tree_manager_type != "none")
+        problem->setTreeManager(AutoConfFactoryTreeManager::get().create(tree_manager_type, "tree manager", _server));
+
     // Prior
     Eigen::VectorXd prior_state = _server.getParam<Eigen::VectorXd>("problem/prior/state");
     Eigen::MatrixXd prior_cov   = _server.getParam<Eigen::MatrixXd>("problem/prior/cov");
@@ -471,12 +480,22 @@ std::string Problem::getFrameStructure() const
     return frame_structure_;
 }
 
+void Problem::setTreeManager(TreeManagerBasePtr _gm)
+{
+    if (tree_manager_)
+        tree_manager_->setProblem(nullptr);
+    tree_manager_ = _gm;
+    tree_manager_->setProblem(shared_from_this());
+
+}
+
 void Problem::addProcessorIsMotion(IsMotionPtr _processor_motion_ptr)
 {
     processor_is_motion_list_.push_back(_processor_motion_ptr);
 }
 
-void Problem::clearProcessorIsMotion(IsMotionPtr proc){
+void Problem::clearProcessorIsMotion(IsMotionPtr proc)
+{
     auto it = std::find(processor_is_motion_list_.begin(), processor_is_motion_list_.end(), proc);
     if (it != processor_is_motion_list_.end()){
         processor_is_motion_list_.erase(it);
@@ -528,6 +547,10 @@ void Problem::keyFrameCallback(FrameBasePtr _keyframe_ptr, ProcessorBasePtr _pro
                           " microseconds: ", duration.count());
 #endif
             }
+
+    // notify tree manager
+    if (tree_manager_)
+        tree_manager_->keyFrameCallback(_keyframe_ptr);
 }
 
 bool Problem::permitAuxFrame(ProcessorBasePtr _processor_ptr) const
@@ -909,6 +932,10 @@ FrameBasePtr Problem::setPrior(const Eigen::VectorXd& _prior_state, const Eigen:
                 if ( !processor->isMotion() )
                     processor->keyFrameCallback(origin_keyframe, _time_tolerance);
 
+        // Notify tree manager
+        if (tree_manager_)
+            tree_manager_->keyFrameCallback(origin_keyframe);
+
         return origin_keyframe;
     }
     else
diff --git a/src/processor/processor_motion.cpp b/src/processor/processor_motion.cpp
index e2db67fcd9271ce4cd87652f1c33363be4c34bab..3d4cb43942b60b1bf9103593483d4ca8d394eb48 100644
--- a/src/processor/processor_motion.cpp
+++ b/src/processor/processor_motion.cpp
@@ -1,3 +1,10 @@
+/**
+ * \file processor_motion.cpp
+ *
+ *  Created on: 15/03/2016
+ *      \author: jsola
+ */
+
 
 
 #include "core/processor/processor_motion.h"
diff --git a/src/processor/processor_tracker.cpp b/src/processor/processor_tracker.cpp
index 97f3f6c0b0b7f6a14afdffbe2cb460ce4c94fbdc..6119b6c487b56f2a7c48af70131e0570fa54d1dd 100644
--- a/src/processor/processor_tracker.cpp
+++ b/src/processor/processor_tracker.cpp
@@ -170,7 +170,7 @@ void ProcessorTracker::processCapture(CaptureBasePtr _incoming_ptr)
                 // process
                 processNew(params_tracker_->max_new_features);
 
-                //TODO abort KF if last_ptr_->getFeatureList().size() < params_tracker_->min_features_for_keyframe
+                //TODO abort KF if known_features_last_.size() < params_tracker_->min_features_for_keyframe
 
                 // We create a KF
                 // set KF on last
diff --git a/src/processor/processor_tracker_feature.cpp b/src/processor/processor_tracker_feature.cpp
index a0f48d7c771527402b7adffd688e837c0cef7e3f..878f4e24dc31b64627cc3f5959c9cdf80c73f96f 100644
--- a/src/processor/processor_tracker_feature.cpp
+++ b/src/processor/processor_tracker_feature.cpp
@@ -47,7 +47,10 @@ unsigned int ProcessorTrackerFeature::processNew(const int& _max_new_features)
 
     // fill the track matrix
     for (auto ftr : new_features_last_)
+    {
+        assert(std::find(known_features_last_.begin(), known_features_last_.end(), ftr) == known_features_last_.end() && "detectNewFeatures() provided a new feature that is already in known_features_last_`");
         track_matrix_.newTrack(ftr);
+    }
 
     // Track new features from last to incoming. This will append new correspondences to matches_last_incoming
     trackFeatures(new_features_last_,
@@ -79,14 +82,14 @@ unsigned int ProcessorTrackerFeature::processKnown()
     matches_last_from_incoming_.clear();
     known_features_incoming_.clear();
 
-    if (!last_ptr_ || last_ptr_->getFeatureList().empty())
+    if (!last_ptr_ || known_features_last_.empty())
     {
         WOLF_TRACE("Empty last feature list, returning...");
         return 0;
     }
 
     // Track features from last_ptr_ to incoming_ptr_
-    trackFeatures(last_ptr_->getFeatureList(),
+    trackFeatures(known_features_last_,
                   incoming_ptr_,
                   known_features_incoming_,
                   matches_last_from_incoming_);
@@ -132,6 +135,9 @@ void ProcessorTrackerFeature::advanceDerived()
 {
     // Reset here the list of correspondences.
     matches_last_from_incoming_.clear();
+    known_features_last_ = std::move(known_features_incoming_);
+    //new_features_incoming should be zero!
+    //known_features_last_.splice(new_features_incoming_);
 
     // // remove last from track matrix in case you want to have only KF in the track matrix
     // track_matrix_.remove(last_ptr_);
@@ -141,6 +147,8 @@ void ProcessorTrackerFeature::resetDerived()
 {
     // Reset here the list of correspondences.
     matches_last_from_incoming_.clear();
+    known_features_last_ = std::move(known_features_incoming_);
+    known_features_last_.splice(known_features_last_.end(), new_features_incoming_);
 
     // Debug
     //for (auto const & pair_trkid_pair : track_matrix_.matches(origin_ptr_, last_ptr_))
diff --git a/src/processor/processor_tracker_landmark.cpp b/src/processor/processor_tracker_landmark.cpp
index f6425f4048c0830bc05bfb1d1dc5ac18f9210dec..0e593a917d9c7715cb16a62a43154cbd53992d58 100644
--- a/src/processor/processor_tracker_landmark.cpp
+++ b/src/processor/processor_tracker_landmark.cpp
@@ -30,6 +30,8 @@ void ProcessorTrackerLandmark::advanceDerived()
 {
     matches_landmark_from_last_ = std::move(matches_landmark_from_incoming_);
     new_features_last_ = std::move(new_features_incoming_);
+    known_features_last_ = std::move(known_features_incoming_);
+    known_features_last_.splice(known_features_last_.end(), new_features_incoming_);
 
     matches_landmark_from_incoming_.clear();
     new_features_incoming_.clear();
@@ -40,6 +42,8 @@ void ProcessorTrackerLandmark::resetDerived()
 {
     matches_landmark_from_last_ = std::move(matches_landmark_from_incoming_);
     new_features_last_ = std::move(new_features_incoming_);
+    known_features_last_ = std::move(known_features_incoming_);
+    known_features_last_.splice(known_features_last_.end(), new_features_incoming_);
 
     matches_landmark_from_incoming_.clear();
     new_features_incoming_.clear();
@@ -129,15 +133,17 @@ void ProcessorTrackerLandmark::emplaceNewLandmarks()
 
 void ProcessorTrackerLandmark::establishFactors()
 {
-    // Loop all features in last_ptr_
-    for (auto last_feature : last_ptr_->getFeatureList())
-    {
-        assert(matches_landmark_from_last_.count(last_feature) == 1);
+    // Loop all features tracked in last_ptr_ (two lists known_features_last_ and new_features_last_)
+    std::list<FeatureBasePtrList> both_lists{known_features_last_, new_features_last_};
+    for (auto feature_list : both_lists)
+        for (auto last_feature : feature_list)
+        {
+            assert(matches_landmark_from_last_.count(last_feature) == 1);
 
-        FactorBasePtr fac_ptr = emplaceFactor(last_feature, matches_landmark_from_last_[last_feature]->landmark_ptr_);
+            FactorBasePtr fac_ptr = emplaceFactor(last_feature, matches_landmark_from_last_[last_feature]->landmark_ptr_);
 
-        assert(fac_ptr->getFeature() != nullptr && "not linked factor returned by emplaceFactor()");
-    }
+            assert(fac_ptr->getFeature() != nullptr && "not linked factor returned by emplaceFactor()");
+        }
 }
 
 } // namespace wolf
diff --git a/src/trajectory/trajectory_base.cpp b/src/trajectory/trajectory_base.cpp
index 428faf954d89ffc8f0d7a88b182cd04a92850c4a..7620c9fa29132561cb0324d60399da97355f7f67 100644
--- a/src/trajectory/trajectory_base.cpp
+++ b/src/trajectory/trajectory_base.cpp
@@ -4,7 +4,7 @@
 namespace wolf {
 
 TrajectoryBase::TrajectoryBase(const std::string& _frame_structure) :
-    NodeBase("TRAJECTORY", "Base"),
+    NodeBase("TRAJECTORY", "TrajectoryBase"),
     frame_structure_(_frame_structure),
     last_key_frame_ptr_(nullptr),
     last_key_or_aux_frame_ptr_(nullptr)
diff --git a/src/tree_manager/tree_manager_sliding_window.cpp b/src/tree_manager/tree_manager_sliding_window.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7e59cd114f691e24ea04c1a7dc218501c65d31ca
--- /dev/null
+++ b/src/tree_manager/tree_manager_sliding_window.cpp
@@ -0,0 +1,43 @@
+#include "core/tree_manager/tree_manager_sliding_window.h"
+
+namespace wolf
+{
+
+void TreeManagerSlidingWindow::keyFrameCallback(FrameBasePtr _key_frame)
+{
+    int n_kf(0);
+    FrameBasePtr first_KF(nullptr), second_KF(nullptr);
+    for (auto frm : getProblem()->getTrajectory()->getFrameList())
+    {
+        if (frm->isKey())
+        {
+            n_kf++;
+            if (first_KF == nullptr)
+                first_KF = frm;
+            else if (second_KF == nullptr)
+                second_KF = frm;
+        }
+    }
+
+    // remove first KF if too many KF
+    if (n_kf > params_sw_->n_key_frames)
+    {
+        WOLF_DEBUG("TreeManagerSlidingWindow removing first frame");
+        first_KF->remove(params_sw_->viral_remove_empty_parent);
+        if (params_sw_->fix_first_key_frame)
+        {
+            WOLF_DEBUG("TreeManagerSlidingWindow fixing new first frame");
+            second_KF->fix();
+        }
+    }
+}
+
+} /* namespace wolf */
+
+// Register in the FactoryTreeManager
+#include "core/tree_manager/factory_tree_manager.h"
+namespace wolf {
+WOLF_REGISTER_TREE_MANAGER("TreeManagerSlidingWindow", TreeManagerSlidingWindow);
+WOLF_REGISTER_TREE_MANAGER_AUTO("TreeManagerSlidingWindow", TreeManagerSlidingWindow);
+} // namespace wolf
+
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index db82caf1fc34b83b2509fe7d4f3ac4d6cc9e8c82..dc7cfae429f38b83a414229f78a70b01cc5ba53f 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -149,6 +149,10 @@ target_link_libraries(gtest_track_matrix ${PROJECT_NAME})
 wolf_add_gtest(gtest_trajectory gtest_trajectory.cpp)
 target_link_libraries(gtest_trajectory ${PROJECT_NAME})
 
+# TreeManager class test
+wolf_add_gtest(gtest_tree_manager gtest_tree_manager.cpp)
+target_link_libraries(gtest_tree_manager ${PROJECT_NAME})
+
 # ------- Now Derived classes ----------
 
 IF (Ceres_FOUND)
@@ -173,6 +177,10 @@ target_link_libraries(gtest_factor_block_difference ${PROJECT_NAME})
 wolf_add_gtest(gtest_factor_diff_drive gtest_factor_diff_drive.cpp)
 target_link_libraries(gtest_factor_diff_drive ${PROJECT_NAME})
 
+# FactorOdom2d class test
+wolf_add_gtest(gtest_factor_odom_2d gtest_factor_odom_2d.cpp)
+target_link_libraries(gtest_factor_odom_2d ${PROJECT_NAME})
+
 # FactorOdom3d class test
 wolf_add_gtest(gtest_factor_odom_3d gtest_factor_odom_3d.cpp)
 target_link_libraries(gtest_factor_odom_3d ${PROJECT_NAME})
@@ -185,6 +193,14 @@ target_link_libraries(gtest_factor_pose_2d ${PROJECT_NAME})
 wolf_add_gtest(gtest_factor_pose_3d gtest_factor_pose_3d.cpp)
 target_link_libraries(gtest_factor_pose_3d ${PROJECT_NAME})
 
+# FactorRelativePose2dWithExtrinsics class test
+wolf_add_gtest(gtest_factor_relative_pose_2d_with_extrinsics gtest_factor_relative_pose_2d_with_extrinsics.cpp)
+target_link_libraries(gtest_factor_relative_pose_2d_with_extrinsics ${PROJECT_NAME})
+
+# FactorRelative2dAnalytic class test
+wolf_add_gtest(gtest_factor_relative_2d_analytic gtest_factor_relative_2d_analytic.cpp)
+target_link_libraries(gtest_factor_relative_2d_analytic ${PROJECT_NAME})
+
 # MakePosDef function test
 wolf_add_gtest(gtest_make_posdef gtest_make_posdef.cpp)
 target_link_libraries(gtest_make_posdef ${PROJECT_NAME})
@@ -229,6 +245,10 @@ target_link_libraries(gtest_processor_tracker_landmark_dummy ${PROJECT_NAME} dum
 wolf_add_gtest(gtest_sensor_diff_drive gtest_sensor_diff_drive.cpp)
 target_link_libraries(gtest_sensor_diff_drive ${PROJECT_NAME})
 
+# TreeManagerSlidingWindow class test
+wolf_add_gtest(gtest_tree_manager_sliding_window gtest_tree_manager_sliding_window.cpp)
+target_link_libraries(gtest_tree_manager_sliding_window ${PROJECT_NAME})
+
 # yaml conversions
 wolf_add_gtest(gtest_yaml_conversions gtest_yaml_conversions.cpp)
 target_link_libraries(gtest_yaml_conversions ${PROJECT_NAME})
diff --git a/test/dummy/factor_dummy_zero_1.h b/test/dummy/factor_dummy_zero_1.h
new file mode 100644
index 0000000000000000000000000000000000000000..ffe372f0cb9f5671cc491f295d38ec24b305da3b
--- /dev/null
+++ b/test/dummy/factor_dummy_zero_1.h
@@ -0,0 +1,45 @@
+#ifndef FACTOR_DUMMY_ZERO_1_H_
+#define FACTOR_DUMMY_ZERO_1_H_
+
+//Wolf includes
+#include "core/factor/factor_autodiff.h"
+
+//#include "ceres/jet.h"
+
+namespace wolf {
+    
+WOLF_PTR_TYPEDEFS(FactorDummyZero1);
+
+//class
+class FactorDummyZero1 : public FactorAutodiff<FactorDummyZero1, 1, 1>
+{
+    public:
+        FactorDummyZero1(const StateBlockPtr& _sb_ptr) :
+             FactorAutodiff<FactorDummyZero1, 1, 1>("FactorDummy1",
+                                                nullptr, nullptr, nullptr, nullptr,
+                                                nullptr,
+                                                false, FAC_ACTIVE,
+                                                _sb_ptr)
+        {
+            //
+        }
+
+        virtual ~FactorDummyZero1() = default;
+
+        virtual std::string getTopology() const override
+        {
+            return std::string("MOTION");
+        }
+
+        template<typename T>
+        bool operator ()(const T* const _st1,
+                         T* _residuals) const
+        {
+            _residuals[0] = _st1[0];
+            return true;
+        }
+};
+
+} // namespace wolf
+
+#endif
diff --git a/test/dummy/factor_dummy_zero_12.h b/test/dummy/factor_dummy_zero_12.h
new file mode 100644
index 0000000000000000000000000000000000000000..3a57aa386d20524fbbec30aa154f555af0fbb9a1
--- /dev/null
+++ b/test/dummy/factor_dummy_zero_12.h
@@ -0,0 +1,155 @@
+#ifndef FACTOR_DUMMY_ZERO_12_H_
+#define FACTOR_DUMMY_ZERO_12_H_
+
+//Wolf includes
+#include "core/factor/factor_autodiff.h"
+
+//#include "ceres/jet.h"
+
+namespace wolf {
+    
+//class
+template <unsigned int ID>
+class FactorDummyZero12 : public FactorAutodiff<FactorDummyZero12<ID>, ID, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12>
+{
+    static const unsigned int id = ID;
+    public:
+        FactorDummyZero12(const StateBlockPtr& _sb1_ptr,
+                          const StateBlockPtr& _sb2_ptr,
+                          const StateBlockPtr& _sb3_ptr,
+                          const StateBlockPtr& _sb4_ptr,
+                          const StateBlockPtr& _sb5_ptr,
+                          const StateBlockPtr& _sb6_ptr,
+                          const StateBlockPtr& _sb7_ptr,
+                          const StateBlockPtr& _sb8_ptr,
+                          const StateBlockPtr& _sb9_ptr,
+                          const StateBlockPtr& _sb10_ptr,
+                          const StateBlockPtr& _sb11_ptr,
+                          const StateBlockPtr& _sb12_ptr) :
+             FactorAutodiff<FactorDummyZero12<ID>, ID, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12>("FactorDummy12",
+                                                nullptr, nullptr, nullptr, nullptr,
+                                                nullptr,
+                                                false, FAC_ACTIVE,
+                                                _sb1_ptr,
+                                                _sb2_ptr,
+                                                _sb3_ptr,
+                                                _sb4_ptr,
+                                                _sb5_ptr,
+                                                _sb6_ptr,
+                                                _sb7_ptr,
+                                                _sb8_ptr,
+                                                _sb9_ptr,
+                                                _sb10_ptr,
+                                                _sb11_ptr,
+                                                _sb12_ptr)
+        {
+            assert(id > 0 && id <= 12);
+        }
+
+        virtual ~FactorDummyZero12() = default;
+
+        virtual std::string getTopology() const override
+        {
+            return std::string("MOTION");
+        }
+
+        template<typename T>
+        bool operator ()(const T* const _st1,
+                         const T* const _st2,
+                         const T* const _st3,
+                         const T* const _st4,
+                         const T* const _st5,
+                         const T* const _st6,
+                         const T* const _st7,
+                         const T* const _st8,
+                         const T* const _st9,
+                         const T* const _st10,
+                         const T* const _st11,
+                         const T* const _st12,
+                         T* _residuals) const
+        {
+            Eigen::Map<Eigen::Matrix<T,ID,1>> residuals(_residuals);
+            switch (id)
+            {
+                case 1:
+                {
+                    Eigen::Map<const Eigen::Matrix<T,ID,1>> st1(_st1);
+                    residuals = st1;
+                    break;
+                }
+                case 2:
+                {
+                    Eigen::Map<const Eigen::Matrix<T,ID,1>> st2(_st2);
+                    residuals = st2;
+                    break;
+                }
+                case 3:
+                {
+                    Eigen::Map<const Eigen::Matrix<T,ID,1>> st3(_st3);
+                    residuals = st3;
+                    break;
+                }
+                case 4:
+                {
+                    Eigen::Map<const Eigen::Matrix<T,ID,1>> st4(_st4);
+                    residuals = st4;
+                    break;
+                }
+                case 5:
+                {
+                    Eigen::Map<const Eigen::Matrix<T,ID,1>> st5(_st5);
+                    residuals = st5;
+                    break;
+                }
+                case 6:
+                {
+                    Eigen::Map<const Eigen::Matrix<T,ID,1>> st6(_st6);
+                    residuals = st6;
+                    break;
+                }
+                case 7:
+                {
+                    Eigen::Map<const Eigen::Matrix<T,ID,1>> st7(_st7);
+                    residuals = st7;
+                    break;
+                }
+                case 8:
+                {
+                    Eigen::Map<const Eigen::Matrix<T,ID,1>> st8(_st8);
+                    residuals = st8;
+                    break;
+                }
+                case 9:
+                {
+                    Eigen::Map<const Eigen::Matrix<T,ID,1>> st9(_st9);
+                    residuals = st9;
+                    break;
+                }
+                case 10:
+                {
+                    Eigen::Map<const Eigen::Matrix<T,ID,1>> st10(_st10);
+                    residuals = st10;
+                    break;
+                }
+                case 11:
+                {
+                    Eigen::Map<const Eigen::Matrix<T,ID,1>> st11(_st11);
+                    residuals = st11;
+                    break;
+                }
+                case 12:
+                {
+                    Eigen::Map<const Eigen::Matrix<T,ID,1>> st12(_st12);
+                    residuals = st12;
+                    break;
+                }
+                default:
+                    throw std::runtime_error("ID not found");
+            }
+            return true;
+        }
+};
+
+} // namespace wolf
+
+#endif
diff --git a/test/dummy/processor_tracker_feature_dummy.cpp b/test/dummy/processor_tracker_feature_dummy.cpp
index 4693ff76fb3bf38ad5a52d6a6754383e9601dbe0..d7eb625c2717769099d4de48dea2b5c30e43cf7c 100644
--- a/test/dummy/processor_tracker_feature_dummy.cpp
+++ b/test/dummy/processor_tracker_feature_dummy.cpp
@@ -58,6 +58,7 @@ unsigned int ProcessorTrackerFeatureDummy::detectNewFeatures(const int& _max_new
                                                              FeatureBasePtrList& _features_out)
 {
     unsigned int max_features = _max_new_features;
+    WOLF_INFO("Detecting " , _max_new_features , " new features..." );
 
     if (max_features == -1)
     {
@@ -70,7 +71,7 @@ unsigned int ProcessorTrackerFeatureDummy::detectNewFeatures(const int& _max_new
     for (unsigned int i = 0; i < max_features; i++)
     {
         FeatureBasePtr ftr = FeatureBase::emplace<FeatureBase>(_capture,
-                                                               "DUMMY FEATURE",
+                                                               "FeatureDummy",
                                                                Eigen::Vector1d::Ones(),
                                                                Eigen::MatrixXd::Ones(1, 1));
         _features_out.push_back(ftr);
@@ -92,26 +93,11 @@ FactorBasePtr ProcessorTrackerFeatureDummy::emplaceFactor(FeatureBasePtr _featur
     return FactorBase::emplace<FactorFeatureDummy>(_feature_ptr, _feature_ptr, _feature_other_ptr, shared_from_this());
 }
 
-ProcessorBasePtr ProcessorTrackerFeatureDummy::create(const std::string& _unique_name,
-                                                      const ParamsProcessorBasePtr _params)
-{
-    auto params = std::static_pointer_cast<ParamsProcessorTrackerFeatureDummy>(_params);
-
-    // if cast failed use default value
-    if (params == nullptr)
-        params = std::make_shared<ParamsProcessorTrackerFeatureDummy>();
-
-    auto  prc_ptr = std::make_shared<ProcessorTrackerFeatureDummy>(params);
-
-    prc_ptr->setName(_unique_name);
-
-    return prc_ptr;
-}
-
 } // namespace wolf
 
 // Register in the ProcessorFactory
 #include "core/processor/factory_processor.h"
 namespace wolf {
 WOLF_REGISTER_PROCESSOR("ProcessorTrackerFeatureDummy", ProcessorTrackerFeatureDummy)
+WOLF_REGISTER_PROCESSOR_AUTO("ProcessorTrackerFeatureDummy", ProcessorTrackerFeatureDummy)
 } // namespace wolf
diff --git a/test/dummy/processor_tracker_feature_dummy.h b/test/dummy/processor_tracker_feature_dummy.h
index 4b42d372942b276ae1784486fe823ff5234f26e1..ee8fa4c5bcf8765004c3eb07f940708832249817 100644
--- a/test/dummy/processor_tracker_feature_dummy.h
+++ b/test/dummy/processor_tracker_feature_dummy.h
@@ -14,7 +14,7 @@
 
 namespace wolf
 {
-    
+
 WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorTrackerFeatureDummy);
 
 struct ParamsProcessorTrackerFeatureDummy : public ParamsProcessorTrackerFeature
@@ -31,7 +31,7 @@ struct ParamsProcessorTrackerFeatureDummy : public ParamsProcessorTrackerFeature
 
 
 WOLF_PTR_TYPEDEFS(ProcessorTrackerFeatureDummy);
-    
+
 //Class
 class ProcessorTrackerFeatureDummy : public ProcessorTrackerFeature
 {
@@ -39,6 +39,10 @@ class ProcessorTrackerFeatureDummy : public ProcessorTrackerFeature
     public:
         ProcessorTrackerFeatureDummy(ParamsProcessorTrackerFeatureDummyPtr _params_tracker_feature);
         virtual ~ProcessorTrackerFeatureDummy();
+
+        // Factory method for high level API
+        WOLF_PROCESSOR_CREATE(ProcessorTrackerFeatureDummy, ProcessorParamsTrackerFeatureDummy);
+
         virtual void configure(SensorBasePtr _sensor) { };
 
     protected:
@@ -101,12 +105,6 @@ class ProcessorTrackerFeatureDummy : public ProcessorTrackerFeature
          * This function emplaces a factor of the appropriate type for the derived processor.
          */
         virtual FactorBasePtr emplaceFactor(FeatureBasePtr _feature_ptr, FeatureBasePtr _feature_other_ptr);
-
-    public:
-
-        static ProcessorBasePtr create(const std::string& _unique_name,
-                                       const ParamsProcessorBasePtr _params);
-
 };
 
 inline ProcessorTrackerFeatureDummy::ProcessorTrackerFeatureDummy(ParamsProcessorTrackerFeatureDummyPtr _params_tracker_feature_dummy) :
diff --git a/test/dummy/processor_tracker_landmark_dummy.cpp b/test/dummy/processor_tracker_landmark_dummy.cpp
index 58519f3d085d67233378ebc813569f933a338d5f..43ba3d8d407b741b5089935c1df37e5bdee41c03 100644
--- a/test/dummy/processor_tracker_landmark_dummy.cpp
+++ b/test/dummy/processor_tracker_landmark_dummy.cpp
@@ -112,4 +112,12 @@ FactorBasePtr ProcessorTrackerLandmarkDummy::emplaceFactor(FeatureBasePtr _featu
     return FactorBase::emplace<FactorLandmarkDummy>(_feature_ptr, _feature_ptr, _landmark_ptr, shared_from_this());
 }
 
-} //namespace wolf
+} // namespace wolf
+
+// Register in the ProcessorFactory
+#include "core/processor/processor_factory.h"
+namespace wolf {
+WOLF_REGISTER_PROCESSOR("ProcessorTrackerLandmarkDummy", ProcessorTrackerLandmarkDummy)
+WOLF_REGISTER_PROCESSOR_AUTO("ProcessorTrackerLandmarkDummy", ProcessorTrackerLandmarkDummy)
+} // namespace wolf
+
diff --git a/test/dummy/processor_tracker_landmark_dummy.h b/test/dummy/processor_tracker_landmark_dummy.h
index fa9c11dcffd6e7d78e1bc7e4e0cc988ce827f1fe..3261481365ebbdba04957d149a165be62368bd41 100644
--- a/test/dummy/processor_tracker_landmark_dummy.h
+++ b/test/dummy/processor_tracker_landmark_dummy.h
@@ -34,6 +34,10 @@ class ProcessorTrackerLandmarkDummy : public ProcessorTrackerLandmark
     public:
         ProcessorTrackerLandmarkDummy(ParamsProcessorTrackerLandmarkDummyPtr _params_tracker_landmark_dummy);
         virtual ~ProcessorTrackerLandmarkDummy();
+
+        // Factory method for high level API
+        WOLF_PROCESSOR_CREATE(ProcessorTrackerLandmarkDummy, ProcessorParamsTrackerLandmarkDummy);
+
         virtual void configure(SensorBasePtr _sensor) { };
 
     protected:
diff --git a/test/dummy/tree_manager_dummy.h b/test/dummy/tree_manager_dummy.h
new file mode 100644
index 0000000000000000000000000000000000000000..379fdd23902daaa5e3ba9d29a3f6a445f9e21373
--- /dev/null
+++ b/test/dummy/tree_manager_dummy.h
@@ -0,0 +1,61 @@
+#ifndef INCLUDE_TREE_MANAGER_DUMMY_H_
+#define INCLUDE_TREE_MANAGER_DUMMY_H_
+
+#include "core/tree_manager/tree_manager_base.h"
+
+namespace wolf
+{
+
+WOLF_STRUCT_PTR_TYPEDEFS(ParamsTreeManagerDummy)
+struct ParamsTreeManagerDummy : public ParamsTreeManagerBase
+{
+    ParamsTreeManagerDummy() = default;
+    ParamsTreeManagerDummy(std::string _unique_name, const ParamsServer& _server):
+        ParamsTreeManagerBase(_unique_name, _server)
+    {
+        toy_param = _server.getParam<double>(prefix + "/toy_param");
+    }
+
+    virtual ~ParamsTreeManagerDummy() = default;
+
+    bool toy_param;
+
+    std::string print() const
+    {
+        return ParamsTreeManagerBase::print() + "\n"
+               + "toy_param: " + std::to_string(toy_param) + "\n";
+    }
+};
+
+WOLF_PTR_TYPEDEFS(TreeManagerDummy)
+
+class TreeManagerDummy : public TreeManagerBase
+{
+    public:
+        TreeManagerDummy(ParamsTreeManagerBasePtr _params) :
+            TreeManagerBase("TreeManagerDummy", _params),
+            n_KF_(0)
+        {};
+        WOLF_TREE_MANAGER_CREATE(TreeManagerDummy, ParamsTreeManagerBase)
+
+        virtual ~TreeManagerDummy(){}
+
+        virtual void keyFrameCallback(FrameBasePtr _KF) override
+        {
+            n_KF_++;
+        };
+
+        int n_KF_;
+};
+
+} /* namespace wolf */
+
+// Register in the FactoryTreeManager
+#include "core/tree_manager/factory_tree_manager.h"
+namespace wolf {
+WOLF_REGISTER_TREE_MANAGER("TreeManagerDummy", TreeManagerDummy)
+WOLF_REGISTER_TREE_MANAGER_AUTO("TreeManagerDummy", TreeManagerDummy)
+
+} /* namespace wolf */
+
+#endif /* INCLUDE_TREE_MANAGER_DUMMY_H_ */
diff --git a/test/gtest_factor_autodiff.cpp b/test/gtest_factor_autodiff.cpp
index 993908461d6b37cae1b24d8701a3612d4dc9c432..0ca75836e54c0661be560a623f484bee0e5c592a 100644
--- a/test/gtest_factor_autodiff.cpp
+++ b/test/gtest_factor_autodiff.cpp
@@ -13,11 +13,360 @@
 #include "core/factor/factor_odom_2d.h"
 #include "core/factor/factor_odom_2d_analytic.h"
 #include "core/factor/factor_autodiff.h"
+#include "dummy/factor_dummy_zero_1.h"
+#include "dummy/factor_dummy_zero_12.h"
 
 using namespace wolf;
 using namespace Eigen;
 
-TEST(CaptureAutodiff, ConstructorOdom2d)
+template <int First, int Last>
+struct static_for
+{
+    template <typename Lambda>
+    static inline constexpr void apply(Lambda const& f)
+    {
+        if (First < Last)
+        {
+            f(std::integral_constant<int, First>{});
+            static_for<First + 1, Last>::apply(f);
+        }
+    }
+};
+template <int N>
+struct static_for<N, N>
+{
+    template <typename Lambda>
+    static inline constexpr void apply(Lambda const& f) {}
+};
+
+
+TEST(FactorAutodiff, AutodiffDummy1)
+{
+    StateBlockPtr sb = std::make_shared<StateBlock>(Eigen::Vector1d::Random());
+
+    auto fac = std::make_shared<FactorDummyZero1>(sb);
+
+    // COMPUTE JACOBIANS
+    std::vector<const double*> states_ptr({sb->getStateData()});
+
+    std::vector<Eigen::MatrixXd> J;
+    Eigen::VectorXd residuals(fac->getSize());
+    fac->evaluate(states_ptr, residuals, J);
+
+    ASSERT_MATRIX_APPROX(J[0], Eigen::Matrix1d::Ones(), wolf::Constants::EPS);
+}
+
+TEST(FactorAutodiff, AutodiffDummy12)
+{
+    StateBlockPtr sb1 = std::make_shared<StateBlock>(Eigen::Vector1d::Random());
+    StateBlockPtr sb2 = std::make_shared<StateBlock>(Eigen::Vector2d::Random());
+    StateBlockPtr sb3 = std::make_shared<StateBlock>(Eigen::Vector3d::Random());
+    StateBlockPtr sb4 = std::make_shared<StateBlock>(Eigen::Vector4d::Random());
+    StateBlockPtr sb5 = std::make_shared<StateBlock>(Eigen::Vector5d::Random());
+    StateBlockPtr sb6 = std::make_shared<StateBlock>(Eigen::Vector6d::Random());
+    StateBlockPtr sb7 = std::make_shared<StateBlock>(Eigen::Vector7d::Random());
+    StateBlockPtr sb8 = std::make_shared<StateBlock>(Eigen::Vector8d::Random());
+    StateBlockPtr sb9 = std::make_shared<StateBlock>(Eigen::Vector9d::Random());
+    StateBlockPtr sb10 = std::make_shared<StateBlock>(Eigen::Vector10d::Random());
+    StateBlockPtr sb11 = std::make_shared<StateBlock>(Eigen::VectorXd::Random(11));
+    StateBlockPtr sb12 = std::make_shared<StateBlock>(Eigen::VectorXd::Random(12));
+
+    std::vector<const double*> states_ptr({sb1->getStateData(),sb2->getStateData(),sb3->getStateData(),sb4->getStateData(),sb5->getStateData(),sb6->getStateData(),sb7->getStateData(),sb8->getStateData(),sb9->getStateData(),sb10->getStateData(),sb11->getStateData(),sb12->getStateData()});
+    std::vector<Eigen::MatrixXd> J;
+    Eigen::VectorXd residuals;
+    unsigned int i;
+    FactorBasePtr fac = nullptr;
+
+    // 1 ------------------------------------------------------------------------
+    fac = std::make_shared<FactorDummyZero12<1>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12);
+    i = fac->getSize();
+
+    // Jacobian
+    J.clear();
+    residuals.resize(i);
+    fac->evaluate(states_ptr, residuals, J);
+
+    std::cout << "i = " << i << std::endl;
+    for (unsigned int j = 0; j < 12; j++)
+    {
+        std::cout << "j = " << j << std::endl;
+        std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl;
+        if (j == i-1)
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS);
+        }
+        else
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS);
+        }
+    }
+
+    // 2 ------------------------------------------------------------------------
+    fac = std::make_shared<FactorDummyZero12<2>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12);
+    i = fac->getSize();
+
+    // Jacobian
+    J.clear();
+    residuals.resize(i);
+    fac->evaluate(states_ptr, residuals, J);
+
+    std::cout << "i = " << i << std::endl;
+    for (unsigned int j = 0; j < 12; j++)
+    {
+        std::cout << "j = " << j << std::endl;
+        std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl;
+        if (j == i-1)
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS);
+        }
+        else
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS);
+        }
+    }
+
+    // 3 ------------------------------------------------------------------------
+    fac = std::make_shared<FactorDummyZero12<3>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12);
+    i = fac->getSize();
+
+    // Jacobian
+    J.clear();
+    residuals.resize(i);
+    fac->evaluate(states_ptr, residuals, J);
+
+    std::cout << "i = " << i << std::endl;
+    for (unsigned int j = 0; j < 12; j++)
+    {
+        std::cout << "j = " << j << std::endl;
+        std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl;
+        if (j == i-1)
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS);
+        }
+        else
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS);
+        }
+    }
+
+    // 4 ------------------------------------------------------------------------
+    fac = std::make_shared<FactorDummyZero12<4>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12);
+    i = fac->getSize();
+
+    // Jacobian
+    J.clear();
+    residuals.resize(i);
+    fac->evaluate(states_ptr, residuals, J);
+
+    std::cout << "i = " << i << std::endl;
+    for (unsigned int j = 0; j < 12; j++)
+    {
+        std::cout << "j = " << j << std::endl;
+        std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl;
+        if (j == i-1)
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS);
+        }
+        else
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS);
+        }
+    }
+
+    // 5 ------------------------------------------------------------------------
+    fac = std::make_shared<FactorDummyZero12<5>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12);
+    i = fac->getSize();
+
+    // Jacobian
+    J.clear();
+    residuals.resize(i);
+    fac->evaluate(states_ptr, residuals, J);
+
+    std::cout << "i = " << i << std::endl;
+    for (unsigned int j = 0; j < 12; j++)
+    {
+        std::cout << "j = " << j << std::endl;
+        std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl;
+        if (j == i-1)
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS);
+        }
+        else
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS);
+        }
+    }
+
+    // 6 ------------------------------------------------------------------------
+    fac = std::make_shared<FactorDummyZero12<6>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12);
+    i = fac->getSize();
+
+    // Jacobian
+    J.clear();
+    residuals.resize(i);
+    fac->evaluate(states_ptr, residuals, J);
+
+    std::cout << "i = " << i << std::endl;
+    for (unsigned int j = 0; j < 12; j++)
+    {
+        std::cout << "j = " << j << std::endl;
+        std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl;
+        if (j == i-1)
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS);
+        }
+        else
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS);
+        }
+    }
+
+    // 7 ------------------------------------------------------------------------
+    fac = std::make_shared<FactorDummyZero12<7>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12);
+    i = fac->getSize();
+
+    // Jacobian
+    J.clear();
+    residuals.resize(i);
+    fac->evaluate(states_ptr, residuals, J);
+
+    std::cout << "i = " << i << std::endl;
+    for (unsigned int j = 0; j < 12; j++)
+    {
+        std::cout << "j = " << j << std::endl;
+        std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl;
+        if (j == i-1)
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS);
+        }
+        else
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS);
+        }
+    }
+
+    // 8 ------------------------------------------------------------------------
+    fac = std::make_shared<FactorDummyZero12<8>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12);
+    i = fac->getSize();
+
+    // Jacobian
+    J.clear();
+    residuals.resize(i);
+    fac->evaluate(states_ptr, residuals, J);
+
+    std::cout << "i = " << i << std::endl;
+    for (unsigned int j = 0; j < 12; j++)
+    {
+        std::cout << "j = " << j << std::endl;
+        std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl;
+        if (j == i-1)
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS);
+        }
+        else
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS);
+        }
+    }
+
+    // 9 ------------------------------------------------------------------------
+    fac = std::make_shared<FactorDummyZero12<9>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12);
+    i = fac->getSize();
+
+    // Jacobian
+    J.clear();
+    residuals.resize(i);
+    fac->evaluate(states_ptr, residuals, J);
+
+    std::cout << "i = " << i << std::endl;
+    for (unsigned int j = 0; j < 12; j++)
+    {
+        std::cout << "j = " << j << std::endl;
+        std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl;
+        if (j == i-1)
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS);
+        }
+        else
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS);
+        }
+    }
+
+    // 10 ------------------------------------------------------------------------
+    fac = std::make_shared<FactorDummyZero12<10>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12);
+    i = fac->getSize();
+
+    // Jacobian
+    J.clear();
+    residuals.resize(i);
+    fac->evaluate(states_ptr, residuals, J);
+
+    std::cout << "i = " << i << std::endl;
+    for (unsigned int j = 0; j < 12; j++)
+    {
+        std::cout << "j = " << j << std::endl;
+        std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl;
+        if (j == i-1)
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS);
+        }
+        else
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS);
+        }
+    }
+
+    // 11 ------------------------------------------------------------------------
+    fac = std::make_shared<FactorDummyZero12<11>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12);
+    i = fac->getSize();
+
+    // Jacobian
+    J.clear();
+    residuals.resize(i);
+    fac->evaluate(states_ptr, residuals, J);
+
+    std::cout << "i = " << i << std::endl;
+    for (unsigned int j = 0; j < 12; j++)
+    {
+        std::cout << "j = " << j << std::endl;
+        std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl;
+        if (j == i-1)
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS);
+        }
+        else
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS);
+        }
+    }
+
+    // 12 ------------------------------------------------------------------------
+    fac = std::make_shared<FactorDummyZero12<12>>(sb1,sb2,sb3,sb4,sb5,sb6,sb7,sb8,sb9,sb10,sb11,sb12);
+    i = fac->getSize();
+
+    // Jacobian
+    J.clear();
+    residuals.resize(i);
+    fac->evaluate(states_ptr, residuals, J);
+
+    std::cout << "i = " << i << std::endl;
+    for (unsigned int j = 0; j < 12; j++)
+    {
+        std::cout << "j = " << j << std::endl;
+        std::cout << "Jacobian size: " << J[j].rows() << " " << J[j].cols() << std::endl;
+        if (j == i-1)
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Identity(i,i), wolf::Constants::EPS);
+        }
+        else
+        {
+            ASSERT_MATRIX_APPROX(J[j], Eigen::MatrixXd::Zero(i,j+1), wolf::Constants::EPS);
+        }
+    }
+}
+
+TEST(FactorAutodiff, EmplaceOdom2d)
 {
     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)));
@@ -44,7 +393,7 @@ TEST(CaptureAutodiff, ConstructorOdom2d)
     ASSERT_TRUE(factor_ptr->getFrameOther());
 }
 
-TEST(CaptureAutodiff, ResidualOdom2d)
+TEST(FactorAutodiff, ResidualOdom2d)
 {
     Eigen::Vector3d f1_pose, f2_pose;
     f1_pose << 2,1,M_PI;
@@ -88,7 +437,7 @@ TEST(CaptureAutodiff, ResidualOdom2d)
     ASSERT_TRUE(residuals.minCoeff() > -1e-9);
 }
 
-TEST(CaptureAutodiff, JacobianOdom2d)
+TEST(FactorAutodiff, JacobianOdom2d)
 {
     Eigen::Vector3d f1_pose, f2_pose;
     f1_pose << 2,1,M_PI;
@@ -166,7 +515,7 @@ TEST(CaptureAutodiff, JacobianOdom2d)
 //    std::cout << "analytic J " << 3 << ":\n" << J3 << std::endl;
 }
 
-TEST(CaptureAutodiff, AutodiffVsAnalytic)
+TEST(FactorAutodiff, AutodiffVsAnalytic)
 {
     Eigen::Vector3d f1_pose, f2_pose;
     f1_pose << 2,1,M_PI;
diff --git a/test/gtest_factor_block_difference.cpp b/test/gtest_factor_block_difference.cpp
index 1e06c7a80377b99197a721e85473319f9bf34862..f661fb37fd65f4f99ecd7015d4e8474688521a18 100644
--- a/test/gtest_factor_block_difference.cpp
+++ b/test/gtest_factor_block_difference.cpp
@@ -66,6 +66,15 @@ class FixtureFactorBlockDifference : public testing::Test
         virtual void TearDown() override {}
 };
 
+TEST_F(FixtureFactorBlockDifference, CheckFactorType)
+{
+    // Feat_->setMeasurement()
+    FactorBlockDifferencePtr Fac = FactorBase::emplace<FactorBlockDifference>(
+        Feat_, KF0_->getP(), KF1_->getP()
+    );    
+    ASSERT_EQ(Fac->getType(), "FactorBlockDifference");
+}
+
 
 TEST_F(FixtureFactorBlockDifference, EqualP)
 {
diff --git a/test/gtest_factor_odom_2d.cpp b/test/gtest_factor_odom_2d.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..76d559a767f962ef7e82c41bffdded012dd4d04e
--- /dev/null
+++ b/test/gtest_factor_odom_2d.cpp
@@ -0,0 +1,109 @@
+#include "core/utils/utils_gtest.h"
+
+#include "core/factor/factor_odom_2d.h"
+#include "core/capture/capture_odom_2d.h"
+#include "core/math/rotations.h"
+
+#include "core/ceres_wrapper/ceres_manager.h"
+
+using namespace Eigen;
+using namespace wolf;
+using std::cout;
+using std::endl;
+
+// Input odometry data and covariance
+Matrix3d data_cov = 0.1*Matrix3d::Identity();
+
+// Problem and solver
+ProblemPtr problem_ptr = Problem::create("PO", 2);
+CeresManager ceres_mgr(problem_ptr);
+
+// Two frames
+FrameBasePtr frm0 = problem_ptr->emplaceFrame(KEY, Vector3d::Zero(), TimeStamp(0));
+FrameBasePtr frm1 = problem_ptr->emplaceFrame(KEY, Vector3d::Zero(), TimeStamp(1));
+
+// Capture, feature and factor from frm1 to frm0
+auto cap1 = CaptureBase::emplace<CaptureOdom2d>(frm1, 1, nullptr, Vector3d::Zero(), data_cov);
+auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", Vector3d::Zero(), data_cov);
+auto fac1 = FactorBase::emplace<FactorOdom2d>(fea1, fea1, frm0, nullptr, false); // create and add
+
+TEST(FactorOdom2d, check_tree)
+{
+    ASSERT_TRUE(problem_ptr->check(0));
+}
+
+TEST(FactorOdom2d, fix_0_solve)
+{
+    for (int i = 0; i < 1e3; i++)
+    {
+        // Random delta
+        Vector3d delta = Vector3d::Random() * 10;
+        pi2pi(delta(2));
+
+        // Random initial pose
+        Vector3d x0 = Vector3d::Random() * 10;
+        pi2pi(x0(2));
+
+        // x1 groundtruth
+        Vector3d x1;
+        x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * delta.head<2>();
+        x1(2) = pi2pi(x0(2) + delta(2));
+
+        // Set states and measurement
+        frm0->setState(x0);
+        frm1->setState(x1);
+        cap1->setData(delta);
+        fea1->setMeasurement(delta);
+
+        // Fix frm0, perturb frm1
+        frm0->fix();
+        frm1->unfix();
+        frm1->perturb(5);
+
+        // solve for frm1
+        std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF);
+
+        ASSERT_POSE2d_APPROX(frm1->getState(), x1, 1e-6);
+    }
+}
+
+TEST(FactorOdom2d, fix_1_solve)
+{
+    for (int i = 0; i < 1e3; i++)
+    {
+        // Random delta
+        Vector3d delta = Vector3d::Random() * 10;
+        pi2pi(delta(2));
+
+        // Random initial pose
+        Vector3d x0 = Vector3d::Random() * 10;
+        pi2pi(x0(2));
+
+        // x1 groundtruth
+        Vector3d x1;
+        x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * delta.head<2>();
+        x1(2) = pi2pi(x0(2) + delta(2));
+
+        // Set states and measurement
+        frm0->setState(x0);
+        frm1->setState(x1);
+        cap1->setData(delta);
+        fea1->setMeasurement(delta);
+
+        // Fix frm1, perturb frm0
+        frm1->fix();
+        frm0->unfix();
+        frm0->perturb(5);
+
+        // solve for frm0
+        std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF);
+
+        ASSERT_POSE2d_APPROX(frm0->getState(), x0, 1e-6);
+    }
+}
+
+int main(int argc, char **argv)
+{
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/gtest_factor_relative_2d_analytic.cpp b/test/gtest_factor_relative_2d_analytic.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fd8e2296c887aeb7ce6a07579eec939964d29a92
--- /dev/null
+++ b/test/gtest_factor_relative_2d_analytic.cpp
@@ -0,0 +1,109 @@
+#include "core/utils/utils_gtest.h"
+
+#include "core/factor/factor_relative_2d_analytic.h"
+#include "core/capture/capture_odom_2d.h"
+#include "core/math/rotations.h"
+
+#include "core/ceres_wrapper/ceres_manager.h"
+
+using namespace Eigen;
+using namespace wolf;
+using std::cout;
+using std::endl;
+
+// Input odometry data and covariance
+Matrix3d data_cov = 0.1*Matrix3d::Identity();
+
+// Problem and solver
+ProblemPtr problem_ptr = Problem::create("PO", 2);
+CeresManager ceres_mgr(problem_ptr);
+
+// Two frames
+FrameBasePtr frm0 = problem_ptr->emplaceFrame(KEY, Vector3d::Zero(), TimeStamp(0));
+FrameBasePtr frm1 = problem_ptr->emplaceFrame(KEY, Vector3d::Zero(), TimeStamp(1));
+
+// Capture, feature and factor from frm1 to frm0
+auto cap1 = CaptureBase::emplace<CaptureOdom2d>(frm1, 1, nullptr, Vector3d::Zero(), data_cov);
+auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", Vector3d::Zero(), data_cov);
+auto fac1 = FactorBase::emplace<FactorRelative2dAnalytic>(fea1, "odom2d", fea1, frm0, nullptr, false); // create and add
+
+TEST(FactorRelative2dAnalytic, check_tree)
+{
+    ASSERT_TRUE(problem_ptr->check(0));
+}
+
+TEST(FactorRelative2dAnalytic, fix_0_solve)
+{
+    for (int i = 0; i < 1e3; i++)
+    {
+        // Random delta
+        Vector3d delta = Vector3d::Random() * 10;
+        pi2pi(delta(2));
+
+        // Random initial pose
+        Vector3d x0 = Vector3d::Random() * 10;
+        pi2pi(x0(2));
+
+        // x1 groundtruth
+        Vector3d x1;
+        x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * delta.head<2>();
+        x1(2) = pi2pi(x0(2) + delta(2));
+
+        // Set states and measurement
+        frm0->setState(x0);
+        frm1->setState(x1);
+        cap1->setData(delta);
+        fea1->setMeasurement(delta);
+
+        // Fix frm0, perturb frm1
+        frm0->fix();
+        frm1->unfix();
+        frm1->perturb(5);
+
+        // solve for frm1
+        std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF);
+
+        ASSERT_POSE2d_APPROX(frm1->getState(), x1, 1e-6);
+    }
+}
+
+TEST(FactorRelative2dAnalytic, fix_1_solve)
+{
+    for (int i = 0; i < 1e3; i++)
+    {
+        // Random delta
+        Vector3d delta = Vector3d::Random() * 10;
+        pi2pi(delta(2));
+
+        // Random initial pose
+        Vector3d x0 = Vector3d::Random() * 10;
+        pi2pi(x0(2));
+
+        // x1 groundtruth
+        Vector3d x1;
+        x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * delta.head<2>();
+        x1(2) = pi2pi(x0(2) + delta(2));
+
+        // Set states and measurement
+        frm0->setState(x0);
+        frm1->setState(x1);
+        cap1->setData(delta);
+        fea1->setMeasurement(delta);
+
+        // Fix frm1, perturb frm0
+        frm1->fix();
+        frm0->unfix();
+        frm0->perturb(5);
+
+        // solve for frm0
+        std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF);
+
+        ASSERT_POSE2d_APPROX(frm0->getState(), x0, 1e-6);
+    }
+}
+
+int main(int argc, char **argv)
+{
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/gtest_factor_relative_pose_2d_with_extrinsics.cpp b/test/gtest_factor_relative_pose_2d_with_extrinsics.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..547b4c9b7402a9b17eb695ea0e555869fb748a58
--- /dev/null
+++ b/test/gtest_factor_relative_pose_2d_with_extrinsics.cpp
@@ -0,0 +1,219 @@
+#include "core/utils/utils_gtest.h"
+
+#include "core/factor/factor_relative_pose_2d_with_extrinsics.h"
+#include "core/capture/capture_odom_2d.h"
+#include "core/sensor/sensor_odom_2d.h"
+#include "core/processor/processor_odom_2d.h"
+#include "core/math/rotations.h"
+
+#include "core/ceres_wrapper/ceres_manager.h"
+
+using namespace Eigen;
+using namespace wolf;
+using std::cout;
+using std::endl;
+
+std::string wolf_root = _WOLF_ROOT_DIR;
+
+// Input odometry data and covariance
+Matrix3d data_cov = 0.1*Matrix3d::Identity();
+
+// Problem and solver
+ProblemPtr problem_ptr = Problem::create("PO", 2);
+CeresManager ceres_mgr(problem_ptr);
+
+// Sensor
+auto sensor_odom2d = problem_ptr->installSensor("SensorOdom2d", "odom", Vector3d(0,0,0), wolf_root + "/test/yaml/sensor_odom_2d.yaml");
+auto processor_odom2d = problem_ptr->installProcessor("ProcessorOdom2d", "odom", sensor_odom2d, std::make_shared<ProcessorParamsOdom2d>());
+
+// Two frames
+FrameBasePtr frm0 = problem_ptr->emplaceFrame(KEY, Vector3d::Zero(), TimeStamp(0));
+FrameBasePtr frm1 = problem_ptr->emplaceFrame(KEY, Vector3d::Zero(), TimeStamp(1));
+
+// Capture, feature and factor from frm1 to frm0
+auto cap1 = CaptureBase::emplace<CaptureOdom2d>(frm1, 1, sensor_odom2d, Vector3d::Zero(), data_cov);
+auto fea1 = FeatureBase::emplace<FeatureBase>(cap1, "FeatureOdom2d", Vector3d::Zero(), data_cov);
+auto fac1 = FactorBase::emplace<FactorRelativePose2dWithExtrinsics>(fea1, fea1, frm0, processor_odom2d, false); // create and add
+
+TEST(FactorRelativePose2dWithExtrinsics, check_tree)
+{
+    ASSERT_TRUE(problem_ptr->check(0));
+}
+
+TEST(FactorRelativePose2dWithExtrinsics, fix_0_solve)
+{
+    for (int i = 0; i < 1e3; i++)
+    {
+        // Random delta
+        Vector3d delta = Vector3d::Random() * 10;
+        pi2pi(delta(2));
+
+        // Random initial pose
+        Vector3d x0 = Vector3d::Random() * 10;
+        pi2pi(x0(2));
+
+        // Random extrinsics
+        Vector3d xs = Vector3d::Random();
+        pi2pi(xs(2));
+
+        // x1 groundtruth
+        Vector3d x1;
+        x1(2) = pi2pi(x0(2) + delta(2));
+        x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * (xs.head<2>() + Rotation2Dd(xs(2)) * delta.head<2>()) - Rotation2Dd(x1(2)) * xs.head<2>();
+
+        // Set states and measurement
+        frm0->setState(x0);
+        frm1->setState(x1);
+        cap1->setData(delta);
+        fea1->setMeasurement(delta);
+        sensor_odom2d->setState(xs);
+
+        // Perturb frm1, fix the rest
+        frm0->fix();
+        frm1->unfix();
+        sensor_odom2d->getP()->fix();
+        sensor_odom2d->getO()->fix();
+        frm1->perturb(5);
+
+        // solve for frm1
+        std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF);
+
+        ASSERT_POSE2d_APPROX(frm1->getState(), x1, 1e-6);
+    }
+}
+
+TEST(FactorRelativePose2dWithExtrinsics, fix_1_solve)
+{
+    for (int i = 0; i < 1e3; i++)
+    {
+        // Random delta
+        Vector3d delta = Vector3d::Random() * 10;
+        pi2pi(delta(2));
+
+        // Random initial pose
+        Vector3d x0 = Vector3d::Random() * 10;
+        pi2pi(x0(2));
+
+        // Random extrinsics
+        Vector3d xs = Vector3d::Random();
+        pi2pi(xs(2));
+
+        // x1 groundtruth
+        Vector3d x1;
+        x1(2) = pi2pi(x0(2) + delta(2));
+        x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * (xs.head<2>() + Rotation2Dd(xs(2)) * delta.head<2>()) - Rotation2Dd(x1(2)) * xs.head<2>();
+
+        // Set states and measurement
+        frm0->setState(x0);
+        frm1->setState(x1);
+        cap1->setData(delta);
+        fea1->setMeasurement(delta);
+        sensor_odom2d->setState(xs);
+
+        // Perturb frm0, fix the rest
+        frm1->fix();
+        frm0->unfix();
+        sensor_odom2d->getP()->fix();
+        sensor_odom2d->getO()->fix();
+        frm0->perturb(5);
+
+        // solve for frm0
+        std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF);
+
+        ASSERT_POSE2d_APPROX(frm0->getState(), x0, 1e-6);
+    }
+}
+
+TEST(FactorRelativePose2dWithExtrinsics, extrinsics_p_solve)
+{
+    for (int i = 0; i < 1e3; i++)
+    {
+        // Random delta
+        Vector3d delta = Vector3d::Random() * 10;
+        pi2pi(delta(2));
+
+        // Random initial pose
+        Vector3d x0 = Vector3d::Random() * 10;
+        pi2pi(x0(2));
+
+        // Random extrinsics
+        Vector3d xs = Vector3d::Random();
+        pi2pi(xs(2));
+
+        // x1 groundtruth
+        Vector3d x1;
+        x1(2) = pi2pi(x0(2) + delta(2));
+        x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * (xs.head<2>() + Rotation2Dd(xs(2)) * delta.head<2>()) - Rotation2Dd(x1(2)) * xs.head<2>();
+
+        // Set states and measurement
+        frm0->setState(x0);
+        frm1->setState(x1);
+        cap1->setData(delta);
+        fea1->setMeasurement(delta);
+        sensor_odom2d->setState(xs);
+
+        // Perturb sensor P, fix the rest
+        frm1->fix();
+        frm0->fix();
+        sensor_odom2d->getP()->unfix();
+        sensor_odom2d->getO()->fix();
+        sensor_odom2d->getP()->perturb(1);
+
+        // solve for frm0
+        std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF);
+
+        ASSERT_POSE2d_APPROX(sensor_odom2d->getState(), xs, 1e-6);
+    }
+}
+
+TEST(FactorRelativePose2dWithExtrinsics, extrinsics_o_solve)
+{
+    for (int i = 0; i < 1e3; i++)
+    {
+        // Random delta
+        Vector3d delta = Vector3d::Random() * 10;
+        pi2pi(delta(2));
+
+        // Random initial pose
+        Vector3d x0 = Vector3d::Random() * 10;
+        pi2pi(x0(2));
+
+        // Random extrinsics
+        Vector3d xs = Vector3d::Random();
+        pi2pi(xs(2));
+
+        // x1 groundtruth
+        Vector3d x1;
+        x1(2) = pi2pi(x0(2) + delta(2));
+        x1.head<2>() = x0.head<2>() + Rotation2Dd(x0(2)) * (xs.head<2>() + Rotation2Dd(xs(2)) * delta.head<2>()) - Rotation2Dd(x1(2)) * xs.head<2>();
+
+        // Set states and measurement
+        frm0->setState(x0);
+        frm1->setState(x1);
+        cap1->setData(delta);
+        fea1->setMeasurement(delta);
+        sensor_odom2d->setState(xs);
+
+        //std::cout << "Sensor O: " << sensor_odom2d->getO()->getState().transpose() << std::endl;
+
+        // Perturb sensor O, fix the rest
+        frm1->fix();
+        frm0->fix();
+        sensor_odom2d->getP()->fix();
+        sensor_odom2d->getO()->unfix();
+        sensor_odom2d->getO()->perturb(.2);
+
+        //std::cout << "Sensor O (perturbed): " << sensor_odom2d->getO()->getState().transpose() << std::endl;
+
+        // solve for frm0
+        std::string report = ceres_mgr.solve(SolverManager::ReportVerbosity::BRIEF);
+
+        ASSERT_POSE2d_APPROX(sensor_odom2d->getState(), xs, 1e-6);
+    }
+}
+
+int main(int argc, char **argv)
+{
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/gtest_processor_base.cpp b/test/gtest_processor_base.cpp
index f41c0dec436396a0dafffe3a4e549bfcd739c2b0..cf7cd9d0998b278a74d6f29fc8fcd9d6998fb37a 100644
--- a/test/gtest_processor_base.cpp
+++ b/test/gtest_processor_base.cpp
@@ -23,14 +23,6 @@
 using namespace wolf;
 using namespace Eigen;
 
-
-// Register in the ProcessorFactory
-#include "core/processor/factory_processor.h"
-namespace wolf {
-WOLF_REGISTER_PROCESSOR("TRACKER FEATURE DUMMY", ProcessorTrackerFeatureDummy)
-} // namespace wolf
-
-
 TEST(ProcessorBase, IsMotion)
 {
     using namespace wolf;
@@ -84,11 +76,13 @@ TEST(ProcessorBase, KeyFrameCallback)
 
     // Install tracker (sensor and processor)
     auto sens_trk = SensorBase::emplace<SensorBase>(problem->getHardware(),
-                                                    "SensorOdom2d",
+                                                    "SensorTrackerDummy",
                                                     std::make_shared<StateBlock>(Eigen::VectorXd::Zero(2)),
                                                     std::make_shared<StateBlock>(Eigen::VectorXd::Zero(1)),
                                                     std::make_shared<StateBlock>(Eigen::VectorXd::Zero(2)), 2);
-    auto proc_trk = problem->installProcessor("ProcessorTrackerFeatureDummy",  "dummy", sens_trk);
+    auto proc_trk_params = make_shared<ProcessorParamsTrackerFeatureDummy>();
+    proc_trk_params->time_tolerance = dt/2;
+    auto proc_trk = problem->installProcessor("ProcessorTrackerFeatureDummy",  "dummy", sens_trk, proc_trk_params);
 
     // Install odometer (sensor and processor)
     SensorBasePtr sens_odo = problem->installSensor("SensorOdom2d", "odometer", Vector3d(0,0,0), wolf_root + "/test/yaml/sensor_odom_2d.yaml");
@@ -137,4 +131,3 @@ int main(int argc, char **argv)
   testing::InitGoogleTest(&argc, argv);
   return RUN_ALL_TESTS();
 }
-
diff --git a/test/gtest_tree_manager.cpp b/test/gtest_tree_manager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5799117ffa523a9cbf5132ed504fa1525001c0ae
--- /dev/null
+++ b/test/gtest_tree_manager.cpp
@@ -0,0 +1,105 @@
+#include "core/utils/utils_gtest.h"
+#include "core/utils/logging.h"
+
+#include "core/problem/problem.h"
+#include "dummy/tree_manager_dummy.h"
+#include "core/yaml/parser_yaml.h"
+
+using namespace wolf;
+using namespace Eigen;
+
+std::string wolf_root = _WOLF_ROOT_DIR;
+
+TEST(TreeManager, make_shared)
+{
+    ProblemPtr P = Problem::create("PO", 2);
+
+    auto ParamsGM = std::make_shared<ParamsTreeManagerBase>();
+
+    auto GM = std::make_shared<TreeManagerDummy>(ParamsGM);
+
+    P->setTreeManager(GM);
+
+    ASSERT_EQ(std::static_pointer_cast<TreeManagerDummy>(P->getTreeManager())->n_KF_, 0);
+    ASSERT_EQ(P->getTreeManager(), GM);
+}
+
+TEST(TreeManager, createParams)
+{
+    ProblemPtr P = Problem::create("PO", 2);
+
+    auto ParamsGM = std::make_shared<ParamsTreeManagerBase>();
+
+    auto GM = TreeManagerDummy::create("tree_manager", ParamsGM);
+
+    ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerDummy>(GM) != nullptr);
+
+    P->setTreeManager(GM);
+
+    ASSERT_EQ(std::static_pointer_cast<TreeManagerDummy>(P->getTreeManager())->n_KF_, 0);
+    ASSERT_EQ(P->getTreeManager(), GM);
+}
+
+TEST(TreeManager, createParamServer)
+{
+    ProblemPtr P = Problem::create("PO", 2);
+
+    ParserYAML parser = ParserYAML("test/yaml/params_tree_manager1.yaml", wolf_root);
+    ParamsServer server = ParamsServer(parser.getParams());
+
+    auto GM = TreeManagerDummy::create("tree_manager", server);
+
+    ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerDummy>(GM) != nullptr);
+
+    P->setTreeManager(GM);
+
+    ASSERT_EQ(std::static_pointer_cast<TreeManagerDummy>(P->getTreeManager())->n_KF_, 0);
+    ASSERT_EQ(P->getTreeManager(), GM);
+}
+
+TEST(TreeManager, autoConf)
+{
+
+    ParserYAML parser = ParserYAML("test/yaml/params_tree_manager1.yaml", wolf_root);
+    ParamsServer server = ParamsServer(parser.getParams());
+
+    ProblemPtr P = Problem::autoSetup(server);
+
+    ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerDummy>(P->getTreeManager()) != nullptr);
+    ASSERT_EQ(std::static_pointer_cast<TreeManagerDummy>(P->getTreeManager())->n_KF_, 1); // prior KF
+}
+
+TEST(TreeManager, autoConfNone)
+{
+
+    ParserYAML parser = ParserYAML("test/yaml/params_tree_manager2.yaml", wolf_root);
+    ParamsServer server = ParamsServer(parser.getParams());
+
+    ProblemPtr P = Problem::autoSetup(server);
+
+    ASSERT_TRUE(P->getTreeManager() == nullptr); // params_tree_manager2.yaml problem/tree_manager/type: None
+}
+
+TEST(TreeManager, keyFrameCallback)
+{
+    ProblemPtr P = Problem::create("PO", 3);
+
+    auto ParamsGM = std::make_shared<ParamsTreeManagerBase>();
+
+    auto GM = std::make_shared<TreeManagerDummy>(ParamsGM);
+
+    P->setTreeManager(GM);
+
+    ASSERT_EQ(GM->n_KF_, 0);
+
+    auto F0 = P->emplaceFrame("PO", 3,    KEY, VectorXd(7),  TimeStamp(0.0));
+    P->keyFrameCallback(F0, nullptr, 0);
+
+    ASSERT_EQ(GM->n_KF_, 1);
+}
+
+int main(int argc, char **argv)
+{
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/gtest_tree_manager_sliding_window.cpp b/test/gtest_tree_manager_sliding_window.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ed3a8052bfb4a73b4395cc885904d8f752af91d2
--- /dev/null
+++ b/test/gtest_tree_manager_sliding_window.cpp
@@ -0,0 +1,267 @@
+#include "core/utils/utils_gtest.h"
+#include "core/utils/logging.h"
+
+#include "core/problem/problem.h"
+#include "core/tree_manager/tree_manager_sliding_window.h"
+#include "core/yaml/parser_yaml.h"
+#include "core/capture/capture_void.h"
+#include "core/feature/feature_base.h"
+#include "core/factor/factor_odom_3d.h"
+#include "core/factor/factor_pose_3d.h"
+
+using namespace wolf;
+using namespace Eigen;
+
+std::string wolf_root = _WOLF_ROOT_DIR;
+
+TEST(TreeManagerSlidingWindow, make_shared)
+{
+    ProblemPtr P = Problem::create("PO", 2);
+
+    auto ParamsGM = std::make_shared<ParamsTreeManagerSlidingWindow>();
+
+    auto GM = std::make_shared<TreeManagerSlidingWindow>(ParamsGM);
+
+    P->setTreeManager(GM);
+
+    ASSERT_EQ(P->getTreeManager(), GM);
+}
+
+TEST(TreeManagerSlidingWindow, createParams)
+{
+    ProblemPtr P = Problem::create("PO", 2);
+
+    auto ParamsGM = std::make_shared<ParamsTreeManagerSlidingWindow>();
+
+    auto GM = TreeManagerSlidingWindow::create("tree_manager", ParamsGM);
+
+    ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerSlidingWindow>(GM) != nullptr);
+
+    P->setTreeManager(GM);
+
+    ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerSlidingWindow>(P->getTreeManager()) != nullptr);
+    ASSERT_EQ(P->getTreeManager(), GM);
+}
+
+TEST(TreeManagerSlidingWindow, createParamServer)
+{
+    ProblemPtr P = Problem::create("PO", 2);
+
+    ParserYAML parser = ParserYAML("test/yaml/params_tree_manager_sliding_window1.yaml", wolf_root);
+    ParamsServer server = ParamsServer(parser.getParams());
+
+    auto GM = TreeManagerSlidingWindow::create("tree_manager", server);
+
+    ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerSlidingWindow>(GM) != nullptr);
+
+    P->setTreeManager(GM);
+
+    ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerSlidingWindow>(P->getTreeManager()) != nullptr);
+    ASSERT_EQ(P->getTreeManager(), GM);
+}
+
+TEST(TreeManagerSlidingWindow, autoConf)
+{
+    ParserYAML parser = ParserYAML("test/yaml/params_tree_manager_sliding_window1.yaml", wolf_root);
+    ParamsServer server = ParamsServer(parser.getParams());
+
+    ProblemPtr P = Problem::autoSetup(server);
+
+    ASSERT_TRUE(std::dynamic_pointer_cast<TreeManagerSlidingWindow>(P->getTreeManager()) != nullptr);
+}
+
+TEST(TreeManagerSlidingWindow, slidingWindowFixViral)
+{
+    ParserYAML parser = ParserYAML("test/yaml/params_tree_manager_sliding_window1.yaml", wolf_root);
+    ParamsServer server = ParamsServer(parser.getParams());
+
+    ProblemPtr P = Problem::autoSetup(server);
+
+    // FRAME 1 ----------------------------------------------------------
+    auto F1 = P->getTrajectory()->getLastKeyFrame();
+    ASSERT_TRUE(F1 != nullptr);
+
+    Vector7d state = F1->getState();
+    Vector7d zero_disp(state);
+    Matrix6d cov = Matrix6d::Identity();
+
+    // FRAME 2 ----------------------------------------------------------
+    auto F2 = P->emplaceFrame("PO", 3,    KEY, state,  TimeStamp(2));
+    P->keyFrameCallback(F2, nullptr, 0);
+
+    // absolute factor
+    auto C2 = CaptureBase::emplace<CaptureVoid>(F2, TimeStamp(2), nullptr);
+    auto f2 = FeatureBase::emplace<FeatureBase>(C2, "absolute", state, cov);
+    auto c2 = FactorBase::emplace<FactorPose3d>(f2, f2, nullptr, false);
+    // displacement
+    auto C12 = CaptureBase::emplace<CaptureVoid>(F2, TimeStamp(2), nullptr);
+    auto f12 = FeatureBase::emplace<FeatureBase>(C12, "odom", zero_disp, cov);
+    auto c12 = FactorBase::emplace<FactorOdom3d>(f12, f12, F1, nullptr, false);
+
+    // Check no frame removed
+    ASSERT_FALSE(F1->isRemoving());
+
+    // FRAME 3 ----------------------------------------------------------
+    auto F3 = P->emplaceFrame("PO", 3,    KEY, state, TimeStamp(3));
+    P->keyFrameCallback(F3, nullptr, 0);
+
+    // absolute factor
+    auto C3 = CaptureBase::emplace<CaptureVoid>(F3, TimeStamp(3), nullptr);
+    auto f3 = FeatureBase::emplace<FeatureBase>(C3, "absolute", state, cov);
+    auto c3 = FactorBase::emplace<FactorPose3d>(f3, f3, nullptr, false);
+    // displacement
+    auto C23 = CaptureBase::emplace<CaptureVoid>(F3, TimeStamp(3), nullptr);
+    auto f23 = FeatureBase::emplace<FeatureBase>(C23, "odom", zero_disp, cov);
+    auto c23 = FactorBase::emplace<FactorOdom3d>(f23, f23, F2, nullptr, false);
+
+    // Check no frame removed
+    ASSERT_FALSE(F1->isRemoving());
+
+    // FRAME 4 ----------------------------------------------------------
+    auto F4 = P->emplaceFrame("PO", 3,    KEY, state,  TimeStamp(4));
+    P->keyFrameCallback(F4, nullptr, 0);
+
+    // absolute factor
+    auto C4 = CaptureBase::emplace<CaptureVoid>(F4, TimeStamp(4), nullptr);
+    auto f4 = FeatureBase::emplace<FeatureBase>(C4, "absolute", state, cov);
+    auto c4 = FactorBase::emplace<FactorPose3d>(f4, f4, nullptr, false);
+    // displacement
+    auto C34 = CaptureBase::emplace<CaptureVoid>(F4, TimeStamp(4), nullptr);
+    auto f34 = FeatureBase::emplace<FeatureBase>(C34, "odom", zero_disp, cov);
+    auto c34 = FactorBase::emplace<FactorOdom3d>(f34, f34, F3, nullptr, false);
+
+    // Checks
+    ASSERT_TRUE(F1->isRemoving());
+    ASSERT_TRUE(c12->isRemoving());
+    ASSERT_TRUE(C12->isRemoving()); //Virally removed
+    ASSERT_TRUE(f12->isRemoving()); //Virally removed
+    ASSERT_TRUE(F2->isFixed()); //Fixed
+
+    // FRAME 5 ----------------------------------------------------------
+    auto F5 = P->emplaceFrame("PO", 3,    KEY, state,  TimeStamp(5));
+    P->keyFrameCallback(F5, nullptr, 0);
+
+    // absolute factor
+    auto C5 = CaptureBase::emplace<CaptureVoid>(F5, TimeStamp(5), nullptr);
+    auto f5 = FeatureBase::emplace<FeatureBase>(C5, "absolute", state, cov);
+    auto c5 = FactorBase::emplace<FactorPose3d>(f5, f5, nullptr, false);
+    // displacement
+    auto C45 = CaptureBase::emplace<CaptureVoid>(F5, TimeStamp(5), nullptr);
+    auto f45 = FeatureBase::emplace<FeatureBase>(C45, "odom", zero_disp, cov);
+    auto c45 = FactorBase::emplace<FactorOdom3d>(f45, f45, F4, nullptr, false);
+
+    // Checks
+    ASSERT_TRUE(F1->isRemoving());
+    ASSERT_TRUE(c12->isRemoving());
+    ASSERT_TRUE(C12->isRemoving()); //Virally removed
+    ASSERT_TRUE(f12->isRemoving()); //Virally removed
+    ASSERT_TRUE(F2->isRemoving());
+    ASSERT_TRUE(c2->isRemoving());
+    ASSERT_TRUE(C2->isRemoving()); //Virally removed
+    ASSERT_TRUE(f2->isRemoving()); //Virally removed
+    ASSERT_TRUE(c23->isRemoving());
+    ASSERT_TRUE(C23->isRemoving()); //Virally removed
+    ASSERT_TRUE(f23->isRemoving()); //Virally removed
+    ASSERT_TRUE(F3->isFixed()); //Fixed
+}
+
+TEST(TreeManagerSlidingWindow, slidingWindowNoFixNoViral)
+{
+    ParserYAML parser = ParserYAML("test/yaml/params_tree_manager_sliding_window2.yaml", wolf_root);
+    ParamsServer server = ParamsServer(parser.getParams());
+
+    ProblemPtr P = Problem::autoSetup(server);
+
+    // FRAME 1 ----------------------------------------------------------
+    auto F1 = P->getTrajectory()->getLastKeyFrame();
+    ASSERT_TRUE(F1 != nullptr);
+
+    Vector7d state = F1->getState();
+    Vector7d zero_disp(state);
+    Matrix6d cov = Matrix6d::Identity();
+
+    // FRAME 2 ----------------------------------------------------------
+    auto F2 = P->emplaceFrame("PO", 3,    KEY, state,  TimeStamp(2));
+    P->keyFrameCallback(F2, nullptr, 0);
+
+    // absolute factor
+    auto C2 = CaptureBase::emplace<CaptureVoid>(F2, TimeStamp(2), nullptr);
+    auto f2 = FeatureBase::emplace<FeatureBase>(C2, "absolute", state, cov);
+    auto c2 = FactorBase::emplace<FactorPose3d>(f2, f2, nullptr, false);
+    // displacement
+    auto C12 = CaptureBase::emplace<CaptureVoid>(F2, TimeStamp(2), nullptr);
+    auto f12 = FeatureBase::emplace<FeatureBase>(C12, "odom", zero_disp, cov);
+    auto c12 = FactorBase::emplace<FactorOdom3d>(f12, f12, F1, nullptr, false);
+
+    // Check no frame removed
+    ASSERT_FALSE(F1->isRemoving());
+
+    // FRAME 3 ----------------------------------------------------------
+    auto F3 = P->emplaceFrame("PO", 3,    KEY, state, TimeStamp(3));
+    P->keyFrameCallback(F3, nullptr, 0);
+
+    // absolute factor
+    auto C3 = CaptureBase::emplace<CaptureVoid>(F3, TimeStamp(3), nullptr);
+    auto f3 = FeatureBase::emplace<FeatureBase>(C3, "absolute", state, cov);
+    auto c3 = FactorBase::emplace<FactorPose3d>(f3, f3, nullptr, false);
+    // displacement
+    auto C23 = CaptureBase::emplace<CaptureVoid>(F3, TimeStamp(3), nullptr);
+    auto f23 = FeatureBase::emplace<FeatureBase>(C23, "odom", zero_disp, cov);
+    auto c23 = FactorBase::emplace<FactorOdom3d>(f23, f23, F2, nullptr, false);
+
+    // Check no frame removed
+    ASSERT_FALSE(F1->isRemoving());
+
+    // FRAME 4 ----------------------------------------------------------
+    auto F4 = P->emplaceFrame("PO", 3,    KEY, state,  TimeStamp(4));
+    P->keyFrameCallback(F4, nullptr, 0);
+
+    // absolute factor
+    auto C4 = CaptureBase::emplace<CaptureVoid>(F4, TimeStamp(4), nullptr);
+    auto f4 = FeatureBase::emplace<FeatureBase>(C4, "absolute", state, cov);
+    auto c4 = FactorBase::emplace<FactorPose3d>(f4, f4, nullptr, false);
+    // displacement
+    auto C34 = CaptureBase::emplace<CaptureVoid>(F4, TimeStamp(4), nullptr);
+    auto f34 = FeatureBase::emplace<FeatureBase>(C34, "odom", zero_disp, cov);
+    auto c34 = FactorBase::emplace<FactorOdom3d>(f34, f34, F3, nullptr, false);
+
+    // Checks
+    ASSERT_TRUE(F1->isRemoving());
+    ASSERT_TRUE(c12->isRemoving());
+    ASSERT_FALSE(C12->isRemoving()); //Not virally removed
+    ASSERT_FALSE(f12->isRemoving()); //Not virally removed
+    ASSERT_FALSE(F2->isFixed()); //Not fixed
+
+    // FRAME 5 ----------------------------------------------------------
+    auto F5 = P->emplaceFrame("PO", 3,    KEY, state,  TimeStamp(5));
+    P->keyFrameCallback(F5, nullptr, 0);
+
+    // absolute factor
+    auto C5 = CaptureBase::emplace<CaptureVoid>(F5, TimeStamp(5), nullptr);
+    auto f5 = FeatureBase::emplace<FeatureBase>(C5, "absolute", state, cov);
+    auto c5 = FactorBase::emplace<FactorPose3d>(f5, f5, nullptr, false);
+    // displacement
+    auto C45 = CaptureBase::emplace<CaptureVoid>(F5, TimeStamp(5), nullptr);
+    auto f45 = FeatureBase::emplace<FeatureBase>(C45, "odom", zero_disp, cov);
+    auto c45 = FactorBase::emplace<FactorOdom3d>(f45, f45, F4, nullptr, false);
+
+    // Checks
+    ASSERT_TRUE(F1->isRemoving());
+    ASSERT_TRUE(c12->isRemoving());
+    ASSERT_TRUE(C12->isRemoving());
+    ASSERT_TRUE(f12->isRemoving());
+    ASSERT_TRUE(F2->isRemoving());
+    ASSERT_TRUE(c2->isRemoving());
+    ASSERT_TRUE(C2->isRemoving());
+    ASSERT_TRUE(f2->isRemoving());
+    ASSERT_TRUE(c23->isRemoving());
+    ASSERT_FALSE(C23->isRemoving()); //Not virally removed
+    ASSERT_FALSE(f23->isRemoving()); //Not virally removed
+    ASSERT_FALSE(F3->isFixed()); //Not fixed
+}
+
+int main(int argc, char **argv)
+{
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/yaml/params_tree_manager1.yaml b/test/yaml/params_tree_manager1.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..25e8ac8a4417ffec910fee4cac96669a00ebdc4f
--- /dev/null
+++ b/test/yaml/params_tree_manager1.yaml
@@ -0,0 +1,41 @@
+config:
+  problem:
+    frame_structure: "POV"
+    dimension: 3
+    prior:
+      state: [0,0,0,0,0,0,1,0,0,0]
+      cov: [[9,9],.1,0,0,0,0,0,0,0,0, 0,.1,0,0,0,0,0,0,0, 0,0,.1,0,0,0,0,0,0, 0,0,0,.1,0,0,0,0,0, 0,0,0,0,.1,0,0,0,0, 0,0,0,0,0,.1,0,0,0, 0,0,0,0,0,0,.1,0,0, 0,0,0,0,0,0,0,.1,0, 0,0,0,0,0,0,0,0,.1]
+      time_tolerance: 0.1
+      timestamp: 0
+    tree_manager:
+      type: "TreeManagerDummy"
+      toy_param: 0
+  sensors: 
+    -
+      type: "SensorOdom3d"
+      name: "odom"
+      plugin: "core"
+      k_disp_to_disp: 0.1
+      k_disp_to_rot: 0.1
+      k_rot_to_rot: 0.1 
+      min_disp_var: 0.1 
+      min_rot_var: 0.1
+      extrinsic:
+        pose: [1,2,3,0,0,0,1]
+  processors:
+    -
+      type: "ProcessorOdom3d"
+      name: "my_proc_odom3d"
+      sensor_name: "odom"
+      plugin: "core"
+      apply_loss_function: false
+      time_tolerance:         0.01  # seconds
+      keyframe_vote:
+        voting_active:        false
+        voting_aux_active:    false
+        max_time_span:          0.2   # seconds
+        max_buff_length:        10    # motion deltas
+        dist_traveled:          0.5   # meters
+        angle_turned:           0.1   # radians (1 rad approx 57 deg, approx 60 deg)
+      
+      unmeasured_perturbation_std: 0.00111
\ No newline at end of file
diff --git a/test/yaml/params_tree_manager2.yaml b/test/yaml/params_tree_manager2.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..913f5875bfd09750e024fcfeab910ff45d6058ee
--- /dev/null
+++ b/test/yaml/params_tree_manager2.yaml
@@ -0,0 +1,40 @@
+config:
+  problem:
+    frame_structure: "POV"
+    dimension: 3
+    prior:
+      state: [0,0,0,0,0,0,1,0,0,0]
+      cov: [[9,9],.1,0,0,0,0,0,0,0,0, 0,.1,0,0,0,0,0,0,0, 0,0,.1,0,0,0,0,0,0, 0,0,0,.1,0,0,0,0,0, 0,0,0,0,.1,0,0,0,0, 0,0,0,0,0,.1,0,0,0, 0,0,0,0,0,0,.1,0,0, 0,0,0,0,0,0,0,.1,0, 0,0,0,0,0,0,0,0,.1]
+      time_tolerance: 0.1
+      timestamp: 0
+    tree_manager: 
+      type: "None"
+  sensors: 
+    -
+      type: "SensorOdom3d"
+      name: "odom"
+      plugin: "core"
+      k_disp_to_disp: 0.1
+      k_disp_to_rot: 0.1
+      k_rot_to_rot: 0.1 
+      min_disp_var: 0.1 
+      min_rot_var: 0.1
+      extrinsic:
+        pose: [1,2,3,0,0,0,1]
+  processors:
+    -
+      type: "ProcessorOdom3d"
+      name: "my_proc_odom3d"
+      sensor_name: "odom"
+      plugin: "core"
+      apply_loss_function: false
+      time_tolerance:         0.01  # seconds
+      keyframe_vote:
+        voting_active:        false
+        voting_aux_active:    false
+        max_time_span:          0.2   # seconds
+        max_buff_length:        10    # motion deltas
+        dist_traveled:          0.5   # meters
+        angle_turned:           0.1   # radians (1 rad approx 57 deg, approx 60 deg)
+      
+      unmeasured_perturbation_std: 0.00111
\ No newline at end of file
diff --git a/test/yaml/params_tree_manager_sliding_window1.yaml b/test/yaml/params_tree_manager_sliding_window1.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5cbb9e5a787b4ad2e70f9cf7f283ab1747e1279b
--- /dev/null
+++ b/test/yaml/params_tree_manager_sliding_window1.yaml
@@ -0,0 +1,43 @@
+config:
+  problem:
+    frame_structure: "PO"
+    dimension: 3
+    prior:
+      state: [0,0,0,0,0,0,1]
+      cov: [[6,6],.1,0,0,0,0,0, 0,.1,0,0,0,0, 0,0,.1,0,0,0, 0,0,0,.1,0,0, 0,0,0,0,.1,0, 0,0,0,0,0,.1]
+      time_tolerance: 0.1
+      timestamp: 0
+    tree_manager:
+      type: "TreeManagerSlidingWindow"
+      n_key_frames: 3
+      fix_first_key_frame: true
+      viral_remove_empty_parent: true
+  sensors: 
+    -
+      type: "SensorOdom3d"
+      name: "odom"
+      plugin: "core"
+      k_disp_to_disp: 0.1
+      k_disp_to_rot: 0.1
+      k_rot_to_rot: 0.1 
+      min_disp_var: 0.1 
+      min_rot_var: 0.1
+      extrinsic:
+        pose: [1,2,3,0,0,0,1]
+  processors:
+    -
+      type: "ProcessorOdom3d"
+      name: "my_proc_odom3d"
+      sensor_name: "odom"
+      plugin: "core"
+      apply_loss_function: false
+      time_tolerance:         0.01  # seconds
+      keyframe_vote:
+        voting_active:        false
+        voting_aux_active:    false
+        max_time_span:          0.2   # seconds
+        max_buff_length:        10    # motion deltas
+        dist_traveled:          0.5   # meters
+        angle_turned:           0.1   # radians (1 rad approx 57 deg, approx 60 deg)
+      
+      unmeasured_perturbation_std: 0.00111
\ No newline at end of file
diff --git a/test/yaml/params_tree_manager_sliding_window2.yaml b/test/yaml/params_tree_manager_sliding_window2.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..01f41eea97c7cca943d4aa12a143736668c2673f
--- /dev/null
+++ b/test/yaml/params_tree_manager_sliding_window2.yaml
@@ -0,0 +1,43 @@
+config:
+  problem:
+    frame_structure: "PO"
+    dimension: 3
+    prior:
+      state: [0,0,0,0,0,0,1]
+      cov: [[6,6],.1,0,0,0,0,0, 0,.1,0,0,0,0, 0,0,.1,0,0,0, 0,0,0,.1,0,0, 0,0,0,0,.1,0, 0,0,0,0,0,.1]
+      time_tolerance: 0.1
+      timestamp: 0
+    tree_manager:
+      type: "TreeManagerSlidingWindow"
+      n_key_frames: 3
+      fix_first_key_frame: false
+      viral_remove_empty_parent: false
+  sensors: 
+    -
+      type: "SensorOdom3d"
+      name: "odom"
+      plugin: "core"
+      k_disp_to_disp: 0.1
+      k_disp_to_rot: 0.1
+      k_rot_to_rot: 0.1 
+      min_disp_var: 0.1 
+      min_rot_var: 0.1
+      extrinsic:
+        pose: [1,2,3,0,0,0,1]
+  processors:
+    -
+      type: "ProcessorOdom3d"
+      name: "my_proc_odom3d"
+      sensor_name: "odom"
+      plugin: "core"
+      apply_loss_function: false
+      time_tolerance:         0.01  # seconds
+      keyframe_vote:
+        voting_active:        false
+        voting_aux_active:    false
+        max_time_span:          0.2   # seconds
+        max_buff_length:        10    # motion deltas
+        dist_traveled:          0.5   # meters
+        angle_turned:           0.1   # radians (1 rad approx 57 deg, approx 60 deg)
+      
+      unmeasured_perturbation_std: 0.00111
\ No newline at end of file