diff --git a/src/capture_base.cpp b/src/capture_base.cpp
index f307f2bd561e3b30db1a232c45f4792b4a9e44e7..d5d76ba8e37c92d2d17a00cf40b59fea18157b33 100644
--- a/src/capture_base.cpp
+++ b/src/capture_base.cpp
@@ -61,7 +61,6 @@ CaptureBase::CaptureBase(const std::string& _type,
 }
 
 
-
 CaptureBase::~CaptureBase()
 {
     removeStateBlocks();
@@ -169,7 +168,7 @@ void CaptureBase::removeStateBlocks()
         {
             if (getProblem() != nullptr)
             {
-                getProblem()->removeStateBlockPtr(sbp);
+                getProblem()->removeStateBlock(sbp);
             }
             setStateBlockPtr(i, nullptr);
         }
diff --git a/src/capture_base.h b/src/capture_base.h
index 3c14dc5e1cd96908f91e45d81763e2191eae5bf1..06e8541bafb3eff92903e1b982c86dabdcc087f2 100644
--- a/src/capture_base.h
+++ b/src/capture_base.h
@@ -125,8 +125,6 @@ inline void CaptureBase::setProblem(ProblemPtr _problem)
     NodeBase::setProblem(_problem);
     for (auto ft : feature_list_)
         ft->setProblem(_problem);
-    for (auto sb : state_block_vec_)
-        if (sb) sb->setProblem(_problem);
 }
 
 inline void CaptureBase::updateCalibSize()
diff --git a/src/ceres_wrapper/ceres_manager.cpp b/src/ceres_wrapper/ceres_manager.cpp
index 59252fbbdc6a0ec80f1bb3ed91c02c5f8b51a44d..bbd383c66f3ea4edbe0a3caadeebbd5af47d2a02 100644
--- a/src/ceres_wrapper/ceres_manager.cpp
+++ b/src/ceres_wrapper/ceres_manager.cpp
@@ -303,6 +303,7 @@ void CeresManager::removeStateBlock(const StateBlockPtr& state_ptr)
 {
     assert(state_ptr);
     ceres_problem_->RemoveParameterBlock(getAssociatedMemBlockPtr(state_ptr));
+    state_blocks_local_param_.erase(state_ptr);
 }
 
 void CeresManager::updateStateBlockStatus(const StateBlockPtr& state_ptr)
@@ -314,6 +315,42 @@ void CeresManager::updateStateBlockStatus(const StateBlockPtr& state_ptr)
         ceres_problem_->SetParameterBlockVariable(getAssociatedMemBlockPtr(state_ptr));
 }
 
+void CeresManager::updateStateBlockLocalParametrization(const StateBlockPtr& state_ptr)
+{
+    assert(state_ptr != nullptr);
+
+    /* in ceres the easiest way to update (add or remove) a local parameterization
+     * of a state block (parameter block in ceres) is remove & add:
+     *    - the state block: The associated memory block (that identified the parameter_block) is and MUST be the same
+     *    - all involved constraints (residual_blocks in ceres)
+     */
+
+    // get all involved constraints
+    ConstraintBaseList involved_constraints;
+    for (auto pair : ctr_2_costfunction_)
+        for (const StateBlockPtr& st : pair.first->getStateBlockPtrVector())
+            if (st == state_ptr)
+            {
+                // store
+                involved_constraints.push_back(pair.first);
+                break;
+            }
+
+    // Remove all involved constraints (it does not remove any parameter block)
+    for (auto ctr : involved_constraints)
+        removeConstraint(ctr);
+
+    // Remove state block (it removes all involved residual blocks but they just were removed)
+    removeStateBlock(state_ptr);
+
+    // Add state block
+    addStateBlock(state_ptr);
+
+    // Add all involved constraints
+    for (auto ctr : involved_constraints)
+        addConstraint(ctr);
+}
+
 ceres::CostFunctionPtr CeresManager::createCostFunction(const ConstraintBasePtr& _ctr_ptr)
 {
     assert(_ctr_ptr != nullptr);
@@ -349,7 +386,7 @@ void CeresManager::check()
         assert(ctr_2_costfunction_[ctr_res_pair.first].get() == ceres_problem_->GetCostFunctionForResidualBlock(ctr_res_pair.second));
 
         // constraint - residual
-        assert(ctr_res_pair.first == static_cast<const CostFunctionWrapper*>(ceres_problem_->GetCostFunctionForResidualBlock(ctr_res_pair.second))->constraint_ptr_);
+        assert(ctr_res_pair.first == static_cast<const CostFunctionWrapper*>(ceres_problem_->GetCostFunctionForResidualBlock(ctr_res_pair.second))->getConstraintPtr());
 
         // parameter blocks - state blocks
         std::vector<Scalar*> param_blocks;
diff --git a/src/ceres_wrapper/ceres_manager.h b/src/ceres_wrapper/ceres_manager.h
index 3311b1c0761146d75456be3909aa881c993fffa8..ebc8b04e945fb3007aa1e6c6926b450c84211746 100644
--- a/src/ceres_wrapper/ceres_manager.h
+++ b/src/ceres_wrapper/ceres_manager.h
@@ -55,6 +55,8 @@ class CeresManager : public SolverManager
 
         ceres::Solver::Options& getSolverOptions();
 
+        void check();
+
     private:
 
         std::string solveImpl(const ReportVerbosity report_level) override;
@@ -69,9 +71,9 @@ class CeresManager : public SolverManager
 
         void updateStateBlockStatus(const StateBlockPtr& state_ptr) override;
 
-        ceres::CostFunctionPtr createCostFunction(const ConstraintBasePtr& _ctr_ptr);
+        void updateStateBlockLocalParametrization(const StateBlockPtr& state_ptr) override;
 
-        void check();
+        ceres::CostFunctionPtr createCostFunction(const ConstraintBasePtr& _ctr_ptr);
 };
 
 inline ceres::Solver::Summary CeresManager::getSummary()
diff --git a/src/ceres_wrapper/cost_function_wrapper.h b/src/ceres_wrapper/cost_function_wrapper.h
index 65566f2fa314c6a37024e8335990210f347cd437..ffd88191475c23ae409651baedb0099f3aaa4064 100644
--- a/src/ceres_wrapper/cost_function_wrapper.h
+++ b/src/ceres_wrapper/cost_function_wrapper.h
@@ -17,14 +17,19 @@ WOLF_PTR_TYPEDEFS(CostFunctionWrapper);
 
 class CostFunctionWrapper : public ceres::CostFunction
 {
-    public:
+    private:
+
         ConstraintBasePtr constraint_ptr_;
 
+    public:
+
         CostFunctionWrapper(ConstraintBasePtr _constraint_ptr);
 
         virtual ~CostFunctionWrapper();
 
         virtual bool Evaluate(const double* const * parameters, double* residuals, double** jacobians) const;
+
+        ConstraintBasePtr getConstraintPtr() const;
 };
 
 inline CostFunctionWrapper::CostFunctionWrapper(ConstraintBasePtr _constraint_ptr) :
@@ -44,6 +49,11 @@ inline bool CostFunctionWrapper::Evaluate(const double* const * parameters, doub
     return constraint_ptr_->evaluate(parameters, residuals, jacobians);
 }
 
+inline ConstraintBasePtr CostFunctionWrapper::getConstraintPtr() const
+{
+    return constraint_ptr_;
+}
+
 } // namespace wolf
 
 
diff --git a/src/ceres_wrapper/local_parametrization_wrapper.h b/src/ceres_wrapper/local_parametrization_wrapper.h
index 1d81970a963c374cf91a5b283cf443774cb05729..d9e0d9e82671ceb232e47760e2f74a119304ff3e 100644
--- a/src/ceres_wrapper/local_parametrization_wrapper.h
+++ b/src/ceres_wrapper/local_parametrization_wrapper.h
@@ -30,6 +30,8 @@ class LocalParametrizationWrapper : public ceres::LocalParameterization
         virtual int GlobalSize() const;
 
         virtual int LocalSize() const;
+
+        LocalParametrizationBasePtr getLocalParametrizationPtr() const;
 };
 
 using LocalParametrizationWrapperPtr = std::shared_ptr<LocalParametrizationWrapper>;
@@ -55,6 +57,11 @@ inline int LocalParametrizationWrapper::LocalSize() const
     return local_parametrization_ptr_->getLocalSize();
 }
 
+inline LocalParametrizationBasePtr LocalParametrizationWrapper::getLocalParametrizationPtr() const
+{
+    return local_parametrization_ptr_;
+}
+
 } // namespace wolf
 
 #endif
diff --git a/src/constraint_base.cpp b/src/constraint_base.cpp
index ca54791bb95766f72ab7d9e67eb7d717cb8dd081..d88dedbf05f89fcf7386b447520c31a4752a71a0 100644
--- a/src/constraint_base.cpp
+++ b/src/constraint_base.cpp
@@ -60,7 +60,7 @@ void ConstraintBase::remove()
         }
         // add constraint to be removed from solver
         if (getProblem() != nullptr)
-            getProblem()->removeConstraintPtr(shared_from_this());
+            getProblem()->removeConstraint(shared_from_this());
 
         // remove other: {Frame, Capture, Feature, Landmark}
         FrameBasePtr frm_o = frame_other_ptr_.lock();
@@ -126,9 +126,9 @@ void ConstraintBase::setStatus(ConstraintStatus _status)
     else if (_status != status_)
     {
         if (_status == CTR_ACTIVE)
-            getProblem()->addConstraintPtr(shared_from_this());
+            getProblem()->addConstraint(shared_from_this());
         else if (_status == CTR_INACTIVE)
-            getProblem()->removeConstraintPtr(shared_from_this());
+            getProblem()->removeConstraint(shared_from_this());
     }
     status_ = _status;
 }
@@ -142,8 +142,8 @@ void ConstraintBase::setApplyLossFunction(const bool _apply)
         else
         {
             ConstraintBasePtr this_c = shared_from_this();
-            getProblem()->removeConstraintPtr(this_c);
-            getProblem()->addConstraintPtr(this_c);
+            getProblem()->removeConstraint(this_c);
+            getProblem()->addConstraint(this_c);
         }
     }
 }
diff --git a/src/feature_base.cpp b/src/feature_base.cpp
index eb3351129c6b42a51aeef0e2fa98c2fff18df6b1..3cc0b6ca3d64b7299641de401fb67068c0af1b08 100644
--- a/src/feature_base.cpp
+++ b/src/feature_base.cpp
@@ -61,7 +61,7 @@ ConstraintBasePtr FeatureBase::addConstraint(ConstraintBasePtr _co_ptr)
     if (getProblem() != nullptr)
     {
         if (_co_ptr->getStatus() == CTR_ACTIVE)
-            getProblem()->addConstraintPtr(_co_ptr);
+            getProblem()->addConstraint(_co_ptr);
     }
     else
         WOLF_TRACE("WARNING: ADDING CONSTRAINT ", _co_ptr->id(), " TO FEATURE ", this->id(), " NOT CONNECTED WITH PROBLEM.");
diff --git a/src/frame_base.cpp b/src/frame_base.cpp
index 453e54cb58a5c11297866da827539b640c0e2c59..c605ae015c384e235a5409d215a3b2903c1bb439 100644
--- a/src/frame_base.cpp
+++ b/src/frame_base.cpp
@@ -106,7 +106,7 @@ void FrameBase::removeStateBlocks()
         {
             if (getProblem() != nullptr)
             {
-                getProblem()->removeStateBlockPtr(sbp);
+                getProblem()->removeStateBlock(sbp);
             }
             setStateBlockPtr(i, nullptr);
         }
diff --git a/src/frame_base.h b/src/frame_base.h
index 8f49e9b70a9275b590466fe5edcc728cb731605b..d5202bb69e636d7b3f9a8509a0af2ebcb57b6f28 100644
--- a/src/frame_base.h
+++ b/src/frame_base.h
@@ -265,8 +265,6 @@ inline void FrameBase::setProblem(ProblemPtr _problem)
     NodeBase::setProblem(_problem);
     for (auto cap : capture_list_)
         cap->setProblem(_problem);
-    for (auto sb : state_block_vec_)
-        if (sb) sb->setProblem(_problem);
 }
 
 inline ConstraintBaseList& FrameBase::getConstrainedByList()
diff --git a/src/landmark_base.cpp b/src/landmark_base.cpp
index b84c078162635f2320abe46abd6e4c8a3c93cc61..750911457c058acf179d635d24bc289df8237bad 100644
--- a/src/landmark_base.cpp
+++ b/src/landmark_base.cpp
@@ -114,7 +114,7 @@ void LandmarkBase::removeStateBlocks()
         {
             if (getProblem() != nullptr)
             {
-                getProblem()->removeStateBlockPtr(sbp);
+                getProblem()->removeStateBlock(sbp);
             }
             setStateBlockPtr(i, nullptr);
         }
diff --git a/src/landmark_base.h b/src/landmark_base.h
index 5bc32c90083aacb06edf3ce160c54bdc90334c76..e4b721db95a7fe30db760f3a517a10e11f4f6872 100644
--- a/src/landmark_base.h
+++ b/src/landmark_base.h
@@ -110,8 +110,6 @@ namespace wolf{
 inline void LandmarkBase::setProblem(ProblemPtr _problem)
 {
     NodeBase::setProblem(_problem);
-    for (auto sb : state_block_vec_)
-        if (sb) sb->setProblem(_problem);
 }
 
 inline MapBasePtr LandmarkBase::getMapPtr()
diff --git a/src/landmark_polyline_2D.cpp b/src/landmark_polyline_2D.cpp
index d117754206d53c9a409e5e04e6e92548a0249d12..f386803187e25ac323fe85ef6e352b0f0e7de956 100644
--- a/src/landmark_polyline_2D.cpp
+++ b/src/landmark_polyline_2D.cpp
@@ -170,7 +170,7 @@ void LandmarkPolyline2D::defineExtreme(const bool _back)
 
     // remove and add state block without local parameterization
     if (getProblem() != nullptr)
-    	getProblem()->removeStateBlockPtr(state);
+    	getProblem()->removeStateBlock(state);
 
     state->removeLocalParametrization();
 
@@ -182,8 +182,8 @@ void LandmarkPolyline2D::defineExtreme(const bool _back)
         for (auto st_ptr : ctr_ptr->getStateBlockPtrVector())
             if (st_ptr == state && getProblem() != nullptr)
             {
-                getProblem()->removeConstraintPtr(ctr_ptr);
-                getProblem()->addConstraintPtr(ctr_ptr);
+                getProblem()->removeConstraint(ctr_ptr);
+                getProblem()->addConstraint(ctr_ptr);
             }
 
     // update boolean
@@ -304,7 +304,7 @@ void LandmarkPolyline2D::mergePoints(int _remove_id, int _remain_id)
 
     // Remove remove_state
     if (getProblem() != nullptr)
-        getProblem()->removeStateBlockPtr(remove_state);
+        getProblem()->removeStateBlock(remove_state);
     std::cout << "state removed " << std::endl;
 
     // remove element from deque
@@ -329,7 +329,7 @@ void LandmarkPolyline2D::removeStateBlocks()
         {
             if (getProblem() != nullptr)
             {
-                getProblem()->removeStateBlockPtr(sbp);
+                getProblem()->removeStateBlock(sbp);
             }
             point_state_ptr_vector_[i] = nullptr;
         }
diff --git a/src/problem.cpp b/src/problem.cpp
index 8eba70e3f585adb283d479742eb985c61bbcdde9..0b68ffd852a61997178de317f5d12004bd779d90 100644
--- a/src/problem.cpp
+++ b/src/problem.cpp
@@ -368,66 +368,97 @@ void Problem::addLandmarkList(LandmarkBaseList& _lmk_list)
 StateBlockPtr Problem::addStateBlock(StateBlockPtr _state_ptr)
 {
     //std::cout << "Problem::addStateBlockPtr " << _state_ptr.get() << std::endl;
-
-    // set problem
-    _state_ptr->setProblem(shared_from_this());
+    if(std::find(state_block_list_.begin(),state_block_list_.end(),_state_ptr) != state_block_list_.end())
+    {
+        WOLF_WARN("Adding a state block that has already been added");
+        return _state_ptr;
+    }
 
     // add the state unit to the list
     state_block_list_.push_back(_state_ptr);
 
     // Add add notification
-    _state_ptr->addNotification(StateBlock::Notification::ADD);
-
-    // Push all notifications from SB to problem
-    notifyStateBlock(_state_ptr);
+    // Check if there is already a notification for this state block
+    auto notification_it = state_block_notification_map_.find(_state_ptr);
+    if (notification_it != state_block_notification_map_.end() && notification_it->second == ADD)
+    {
+        WOLF_WARN("There is already an ADD notification of this state block");
+    }
+    else
+        state_block_notification_map_[_state_ptr] = ADD;
 
     return _state_ptr;
 }
 
-void Problem::removeStateBlockPtr(StateBlockPtr _state_ptr)
+void Problem::removeStateBlock(StateBlockPtr _state_ptr)
 {
     //std::cout << "Problem::removeStateBlockPtr " << _state_ptr.get() << std::endl;
+    //assert(std::find(state_block_list_.begin(),state_block_list_.end(),_state_ptr) != state_block_list_.end() && "Removing a state_block that hasn't been added or already removed");
+    if(std::find(state_block_list_.begin(),state_block_list_.end(),_state_ptr) == state_block_list_.end())
+    {
+        WOLF_WARN("Removing a state_block that hasn't been added or already removed");
+        return;
+    }
 
     // add the state unit to the list
     state_block_list_.remove(_state_ptr);
 
-    // Add remove notification
-    _state_ptr->addNotification(StateBlock::Notification::REMOVE);
-    notifyStateBlock(_state_ptr);
-}
-
-void Problem::notifyStateBlock(StateBlockPtr _state_ptr)
-{
-    notified_state_block_list_.push_back(_state_ptr);
-    notified_state_block_list_.sort();
-    notified_state_block_list_.unique();
+    // Check if there is already a notification for this state block
+    auto notification_it = state_block_notification_map_.find(_state_ptr);
+    if (notification_it != state_block_notification_map_.end())
+    {
+        if (notification_it->second == REMOVE)
+        {
+            WOLF_WARN("There is already an REMOVE notification of this state block");
+        }
+        // Remove ADD notification
+        else
+        {
+            state_block_notification_map_.erase(notification_it);
+        }
+    }
+    // Add REMOVE notification
+    else
+        state_block_notification_map_[_state_ptr] = REMOVE;
 }
 
-ConstraintBasePtr Problem::addConstraintPtr(ConstraintBasePtr _constraint_ptr)
+ConstraintBasePtr Problem::addConstraint(ConstraintBasePtr _constraint_ptr)
 {
     //std::cout << "Problem::addConstraintPtr " << _constraint_ptr->id() << std::endl;
-    // queue for solver manager
-    constraint_notification_list_.push_back(ConstraintNotification({ADD, _constraint_ptr}));
+
+    // Add ADD notification
+    // Check if there is already a notification for this state block
+    auto notification_it = constraint_notification_map_.find(_constraint_ptr);
+    if (notification_it != constraint_notification_map_.end() && notification_it->second == ADD)
+    {
+        WOLF_WARN("There is already an ADD notification of this constraint");
+    }
+    // Add ADD notification (override in case of REMOVE)
+    else
+        constraint_notification_map_[_constraint_ptr] = ADD;
 
     return _constraint_ptr;
 }
 
-void Problem::removeConstraintPtr(ConstraintBasePtr _constraint_ptr)
+void Problem::removeConstraint(ConstraintBasePtr _constraint_ptr)
 {
     //std::cout << "Problem::removeConstraintPtr " << _constraint_ptr->id() << std::endl;
 
-    // Check if the constraint addition is still as a notification
-    auto ctr_notif_it = constraint_notification_list_.begin();
-    for (; ctr_notif_it != constraint_notification_list_.end(); ctr_notif_it++)
-        if (ctr_notif_it->notification_ == ADD && ctr_notif_it->constraint_ptr_ == _constraint_ptr)
-            break;
-
-    // Remove addition notification
-    if (ctr_notif_it != constraint_notification_list_.end())
-        constraint_notification_list_.erase(ctr_notif_it); // CHECKED shared_ptr is not active after erase
-    // Add remove notification
+    // Check if there is already a notification for this state block
+    auto notification_it = constraint_notification_map_.find(_constraint_ptr);
+    if (notification_it != constraint_notification_map_.end())
+    {
+        if (notification_it->second == REMOVE)
+        {
+            WOLF_WARN("There is already an REMOVE notification of this state block");
+        }
+        // Remove ADD notification
+        else
+            constraint_notification_map_.erase(notification_it);
+    }
+    // Add REMOVE notification
     else
-        constraint_notification_list_.push_back(ConstraintNotification({REMOVE, _constraint_ptr}));
+        constraint_notification_map_[_constraint_ptr] = REMOVE;
 }
 
 void Problem::clearCovariance()
diff --git a/src/problem.h b/src/problem.h
index a8a182a04ba2b7d824663cc8d8320c66db4bddaa..3b5988333bcd7474a90b67bd5013c1863ae4b0f9 100644
--- a/src/problem.h
+++ b/src/problem.h
@@ -27,17 +27,9 @@ namespace wolf {
 enum Notification
 {
     ADD,
-    REMOVE,
-    UPDATE
+    REMOVE
 };
 
-struct ConstraintNotification
-{
-    Notification notification_;
-    ConstraintBasePtr constraint_ptr_;
-};
-
-
 /** \brief Wolf problem node element in the Wolf Tree
  */
 class Problem : public std::enable_shared_from_this<Problem>
@@ -50,9 +42,9 @@ class Problem : public std::enable_shared_from_this<Problem>
         ProcessorMotionPtr  processor_motion_ptr_;
         StateBlockList      state_block_list_;
         std::map<std::pair<StateBlockPtr, StateBlockPtr>, Eigen::MatrixXs> covariances_;
-        std::list<ConstraintNotification> constraint_notification_list_;
         SizeEigen state_size_, state_cov_size_;
-        StateBlockList notified_state_block_list_;
+        std::map<ConstraintBasePtr, Notification> constraint_notification_map_;
+        std::map<StateBlockPtr, Notification> state_block_notification_map_;
         bool prior_is_set_;
 
     private: // CAUTION: THESE METHODS ARE PRIVATE, DO NOT MAKE THEM PUBLIC !!
@@ -259,37 +251,33 @@ class Problem : public std::enable_shared_from_this<Problem>
 
         // Solver management ----------------------------------------
 
-        /** \brief Gets a reference to the state units list
+        /** \brief Gets a reference to the state blocks list
          */
         StateBlockList& getStateBlockList();
 
-        /** \brief Adds a new state block to be added to solver manager
+        /** \brief Notifies a new state block to be added to the solver manager
          */
         StateBlockPtr addStateBlock(StateBlockPtr _state_ptr);
 
-        /** \brief Adds a state block to be removed to solver manager
-         */
-        void removeStateBlockPtr(StateBlockPtr _state_ptr);
-
-        /** \brief Notify State Block change
+        /** \brief Notifies a state block to be removed from the solver manager
          */
-        void notifyStateBlock(StateBlockPtr _state_ptr);
+        void removeStateBlock(StateBlockPtr _state_ptr);
 
-        /** \brief Gets a list of state blocks which state has been changed to be handled by the solver
+        /** \brief Gets a map of constraint notification to be handled by the solver
          */
-        StateBlockList& getNotifiedStateBlockList();
+        std::map<StateBlockPtr,Notification>& getStateBlockNotificationMap();
 
-        /** \brief Gets a queue of constraint notification to be handled by the solver
+        /** \brief Notifies a new constraint to be added to the solver manager
          */
-        std::list<ConstraintNotification>& getConstraintNotificationList();
+        ConstraintBasePtr addConstraint(ConstraintBasePtr _constraint_ptr);
 
-        /** \brief Adds a new constraint to be added to solver manager
+        /** \brief Notifies a constraint to be removed from the solver manager
          */
-        ConstraintBasePtr addConstraintPtr(ConstraintBasePtr _constraint_ptr);
+        void removeConstraint(ConstraintBasePtr _constraint_ptr);
 
-        /** \brief Adds a constraint to be removed to solver manager
+        /** \brief Gets a map of constraint notification to be handled by the solver
          */
-        void removeConstraintPtr(ConstraintBasePtr _constraint_ptr);
+        std::map<ConstraintBasePtr, Notification>& getConstraintNotificationMap();
 
         // Print and check ---------------------------------------
         /**
@@ -328,14 +316,14 @@ inline ProcessorMotionPtr& Problem::getProcessorMotionPtr()
     return processor_motion_ptr_;
 }
 
-inline std::list<ConstraintNotification>& Problem::getConstraintNotificationList()
+inline std::map<StateBlockPtr,Notification>& Problem::getStateBlockNotificationMap()
 {
-    return constraint_notification_list_;
+    return state_block_notification_map_;
 }
 
-inline StateBlockList& Problem::getNotifiedStateBlockList()
+inline std::map<ConstraintBasePtr,Notification>& Problem::getConstraintNotificationMap()
 {
-    return notified_state_block_list_;
+    return constraint_notification_map_;
 }
 
 } // namespace wolf
diff --git a/src/sensor_base.cpp b/src/sensor_base.cpp
index fbd05692eb2b7664f505f7bcccd8ef041952fe4e..7d36d7bf8284f9836cd7d4ee97a00c82665e05cd 100644
--- a/src/sensor_base.cpp
+++ b/src/sensor_base.cpp
@@ -98,7 +98,7 @@ void SensorBase::removeStateBlocks()
         {
             if (getProblem() != nullptr && !extrinsic_dynamic_)
             {
-                getProblem()->removeStateBlockPtr(sbp);
+                getProblem()->removeStateBlock(sbp);
             }
             setStateBlockPtrStatic(i, nullptr);
         }
@@ -355,8 +355,6 @@ void SensorBase::setProblem(ProblemPtr _problem)
     NodeBase::setProblem(_problem);
     for (auto prc : processor_list_)
         prc->setProblem(_problem);
-    for (auto sb : state_block_vec_)
-        if (sb) sb->setProblem(_problem);
 }
 
 } // namespace wolf
diff --git a/src/solver/solver_manager.cpp b/src/solver/solver_manager.cpp
index 8f08f8ae81744c6491285848c42b5dfbf3874056..b6a2e6a40e160a7604063de97ed811933d39e2dd 100644
--- a/src/solver/solver_manager.cpp
+++ b/src/solver/solver_manager.cpp
@@ -14,124 +14,100 @@ SolverManager::SolverManager(const ProblemPtr& _wolf_problem) :
 void SolverManager::update()
 {
     // REMOVE CONSTRAINTS
-    auto ctr_notification_it = wolf_problem_->getConstraintNotificationList().begin();
-    while ( ctr_notification_it != wolf_problem_->getConstraintNotificationList().end() )
+    auto ctr_notification_it = wolf_problem_->getConstraintNotificationMap().begin();
+    while ( ctr_notification_it != wolf_problem_->getConstraintNotificationMap().end() )
     {
-        if (ctr_notification_it->notification_ == REMOVE)
+        if (ctr_notification_it->second == REMOVE)
         {
-            removeConstraint(ctr_notification_it->constraint_ptr_);
-            ctr_notification_it = wolf_problem_->getConstraintNotificationList().erase(ctr_notification_it);
+            removeConstraint(ctr_notification_it->first);
+            ctr_notification_it = wolf_problem_->getConstraintNotificationMap().erase(ctr_notification_it);
         }
         else
             ctr_notification_it++;
     }
 
-    StateBlockList& states = wolf_problem_->getNotifiedStateBlockList();
-
-    for (StateBlockPtr& state : states)
+    // ADD/REMOVE STATE BLOCS
+    auto sb_notification_it = wolf_problem_->getStateBlockNotificationMap().begin();
+    while ( sb_notification_it != wolf_problem_->getStateBlockNotificationMap().end() )
     {
-        const auto notifications = state->consumeNotifications();
+        StateBlockPtr state_ptr = sb_notification_it->first;
 
-        for (const auto notif : notifications)
+        if (sb_notification_it->second == ADD)
         {
-            switch (notif)
+            // only add if not added
+            if (state_blocks_.find(state_ptr) == state_blocks_.end())
+            {
+                state_blocks_.emplace(state_ptr, state_ptr->getState());
+                addStateBlock(state_ptr);
+                // A state_block is added with its last state_ptr, status and local_param, thus, no update is needed for any of those things -> reset flags
+                state_ptr->resetStateUpdated();
+                state_ptr->resetFixUpdated();
+                state_ptr->resetLocalParamUpdated();
+            }
+            else
             {
-                case StateBlock::Notification::ADD:
-                {
-                    const bool registered = state_blocks_.find(state)!=state_blocks_.end();
-
-                    // call addStateBlock only if first time added.
-                    if (!registered)
-                    {
-                        state_blocks_.emplace(state, state->getState());
-                        addStateBlock(state);
-                    }
-
-                    WOLF_DEBUG_COND(registered, "Tried adding an already registered StateBlock.");
-
-                    break;
-                }
-                case StateBlock::Notification::UPDATE_STATE:
-                {
-                    WOLF_DEBUG_COND(state_blocks_.find(state)==state_blocks_.end(),
-                                    "Updating the state of an unregistered StateBlock !");
-
-                    assert(state_blocks_.find(state)!=state_blocks_.end() &&
-                           "Updating the state of an unregistered StateBlock !");
-
-                    Eigen::VectorXs new_state = state->getState();
-                    // We assume the same size for the states in both WOLF and the solver.
-                    std::copy(new_state.data(),new_state.data()+new_state.size(),getAssociatedMemBlockPtr(state));
-
-                    break;
-                }
-                case StateBlock::Notification::UPDATE_FIX:
-                {
-                    WOLF_DEBUG_COND(state_blocks_.find(state)==state_blocks_.end(),
-                                    "Updating the fix state of an unregistered StateBlock !");
-
-                    assert(state_blocks_.find(state)!=state_blocks_.end() &&
-                           "Updating the fix state of an unregistered StateBlock !");
-
-                    if (state_blocks_.find(state)!=state_blocks_.end())
-                    {
-                        updateStateBlockStatus(state);
-                    }
-
-                    break;
-                }
-                case StateBlock::Notification::REMOVE:
-                {
-                    WOLF_DEBUG_COND(state_blocks_.find(state)==state_blocks_.end(),
-                                    "Tried to remove a StateBlock that was not added !");
-
-                    if (state_blocks_.find(state)!=state_blocks_.end())
-                    {
-                        removeStateBlock(state);
-                        state_blocks_.erase(state);
-                    }
-
-                    break;
-                }
-                default:
-                    throw std::runtime_error("SolverManager::update: State Block notification "
-                            "must be ADD, STATE_UPDATE, FIX_UPDATE or REMOVE.");
+                WOLF_DEBUG("Tried adding an already registered StateBlock.");
             }
         }
-    }
-
-    states.clear();
-
-    // ADD CONSTRAINTS
-    while (!wolf_problem_->getConstraintNotificationList().empty())
-    {
-        switch (wolf_problem_->getConstraintNotificationList().front().notification_)
+        else
         {
-            case Notification::ADD:
+            // only remove if it exists
+            if (state_blocks_.find(state_ptr)!=state_blocks_.end())
             {
-                addConstraint(wolf_problem_->getConstraintNotificationList().front().constraint_ptr_);
-
-                break;
+                removeStateBlock(state_ptr);
+                state_blocks_.erase(state_ptr);
+            }
+            else
+            {
+                WOLF_DEBUG("Tried to remove a StateBlock that was not added !");
             }
-            default:
-                throw std::runtime_error("SolverManager::update:"
-                        " Constraint notification must be ADD or REMOVE.");
         }
-
-        wolf_problem_->getConstraintNotificationList().pop_front();
+        // next notification
+        sb_notification_it = wolf_problem_->getStateBlockNotificationMap().erase(sb_notification_it);
     }
 
-    assert(wolf_problem_->getConstraintNotificationList().empty() &&
-           "wolf problem's constraints notification list not empty after update");
-    assert(wolf_problem_->getNotifiedStateBlockList().empty() &&
-           "wolf problem's state_blocks notification list not empty after update");
+    // ADD CONSTRAINTS
+    ctr_notification_it = wolf_problem_->getConstraintNotificationMap().begin();
+    while (ctr_notification_it != wolf_problem_->getConstraintNotificationMap().end())
+    {
+        assert(wolf_problem_->getConstraintNotificationMap().begin()->second == ADD && "unexpected constraint notification value after all REMOVE have been processed, this should be ADD");
+
+        addConstraint(wolf_problem_->getConstraintNotificationMap().begin()->first);
+        ctr_notification_it = wolf_problem_->getConstraintNotificationMap().erase(ctr_notification_it);
+    }
 
-    // UPDATE ALL STATES
-    for (StateBlockPtr& state : states)
+    // UPDATE STATE BLOCKS (state, fix or local parameterization)
+    for (auto state_ptr : wolf_problem_->getStateBlockList())
     {
-        Eigen::VectorXs new_state = state->getState();
-        std::copy(new_state.data(),new_state.data()+new_state.size(),getAssociatedMemBlockPtr(state));
+        assert(state_blocks_.find(state_ptr)!=state_blocks_.end() && "Updating the state of an unregistered StateBlock !");
+
+        // state update
+        if (state_ptr->stateUpdated())
+        {
+            Eigen::VectorXs new_state = state_ptr->getState();
+            // We assume the same size for the states in both WOLF and the solver.
+            std::copy(new_state.data(),new_state.data()+new_state.size(),getAssociatedMemBlockPtr(state_ptr));
+            // reset flag
+            state_ptr->resetStateUpdated();
+        }
+        // fix update
+        if (state_ptr->fixUpdated())
+        {
+            updateStateBlockStatus(state_ptr);
+            // reset flag
+            state_ptr->resetFixUpdated();
+        }
+        // local parameterization update
+        if (state_ptr->localParamUpdated())
+        {
+            updateStateBlockLocalParametrization(state_ptr);
+            // reset flag
+            state_ptr->resetLocalParamUpdated();
+        }
     }
+
+    assert(wolf_problem_->getConstraintNotificationMap().empty() && "wolf problem's constraints notification map not empty after update");
+    assert(wolf_problem_->getStateBlockNotificationMap().empty() && "wolf problem's state_blocks notification map not empty after update");
 }
 
 wolf::ProblemPtr SolverManager::getProblemPtr()
@@ -148,6 +124,7 @@ std::string SolverManager::solve(const ReportVerbosity report_level)
 
     // update StateBlocks with optimized state value.
     /// @todo whatif someone has changed the state notification during opti ??
+    /// JV: I do not see a problem here, the solver provides the optimal state given the constraints, if someone changed the state during optimization, it will be overwritten by the optimal one.
 
     std::map<StateBlockPtr, Eigen::VectorXs>::iterator it = state_blocks_.begin(),
             it_end = state_blocks_.end();
@@ -155,7 +132,7 @@ std::string SolverManager::solve(const ReportVerbosity report_level)
     {
         // Avoid usuless copies
         if (!it->first->isFixed())
-            it->first->setState(it->second, false);
+            it->first->setState(it->second, false); // false = do not raise the flag state_updated_
     }
 
     return report;
diff --git a/src/solver/solver_manager.h b/src/solver/solver_manager.h
index 51325380a31c9d10cba2a3039c62f2216a5b0706..5416067acf84572424f9017c606ab0aa910e92b3 100644
--- a/src/solver/solver_manager.h
+++ b/src/solver/solver_manager.h
@@ -77,6 +77,8 @@ protected:
   virtual void removeStateBlock(const StateBlockPtr& state_ptr) = 0;
 
   virtual void updateStateBlockStatus(const StateBlockPtr& state_ptr) = 0;
+
+  virtual void updateStateBlockLocalParametrization(const StateBlockPtr& state_ptr) = 0;
 };
 
 } // namespace wolf
diff --git a/src/state_block.cpp b/src/state_block.cpp
index 3e53245de9c78b5720d56822c22d4e45447832f0..2599ea21c66351c6a74d40cf4b05bd9f2161d3c4 100644
--- a/src/state_block.cpp
+++ b/src/state_block.cpp
@@ -11,65 +11,29 @@ void StateBlock::setState(const Eigen::VectorXs& _state, const bool _notify)
         state_size_ = state_.size();
     }
 
-    // Notify
+    // Flag
     if (_notify)
-    {
-        addNotification(StateBlock::Notification::UPDATE_STATE);
-        if (getProblem() != nullptr)
-            getProblem()->notifyStateBlock(shared_from_this());
-    }
+        state_updated_.store(true);
 }
 
 void StateBlock::setFixed(bool _fixed)
 {
-    fixed_.store(_fixed);
-    // Notify
-    addNotification(StateBlock::Notification::UPDATE_FIX);
-    if (getProblem() != nullptr)
-        getProblem()->notifyStateBlock(shared_from_this());
-}
+    // Flag
+    if (fixed_.load() != _fixed)
+        fix_updated_.store(true);
 
-void StateBlock::addNotification(const StateBlock::Notification _new_notification)
-{
-    std::lock_guard<std::mutex> lock(notifictions_mut_);
-    if (_new_notification == Notification::ADD)
-    {
-        // When an ADD arrives, the state is already the newest,
-        // thus old instructions can be cleared
-        if (shared_from_this()->notifications_.size() > 0)
-            notifications_.clear();
-
-        // Push ADD notification to the front
-        notifications_.emplace_front(Notification::ADD);
-    }
-    else if (_new_notification == Notification::REMOVE)
-    {
-        // If we want to remove a block that still has an ADD instruction
-        // we can just clear all notifications and just keep the remove
-        if (!notifications_.empty() && notifications_.front() == Notification::ADD)
-            notifications_.clear();
-        else
-        {
-            notifications_.clear();
-            notifications_.emplace_back(Notification::REMOVE);
-        }
-    }
-    else
-        // UPDATE_FIX; UPDATE_STATE
-        notifications_.emplace_back(_new_notification);
-}
-
-StateBlock::Notifications StateBlock::consumeNotifications() const
-{
-    std::lock_guard<std::mutex> lock(notifictions_mut_);
-    return std::move(notifications_);
-}
-
-StateBlock::Notifications StateBlock::getNotifications() const
-{
-    std::lock_guard<std::mutex> lock(notifictions_mut_);
-    return notifications_;
+    // set
+    fixed_.store(_fixed);
 }
 
+//void StateBlock::addToProblem(ProblemPtr _problem_ptr)
+//{
+//    _problem_ptr->addStateBlock(shared_from_this());
+//}
+//
+//void StateBlock::removeFromProblem(ProblemPtr _problem_ptr)
+//{
+//    _problem_ptr->removeStateBlockPtr(shared_from_this());
+//}
 
 }
diff --git a/src/state_block.h b/src/state_block.h
index d2d7c3159d5c0e75d0b7778cbccff4a5601348ac..cdfc94c24dbc488aa8a299c5f058aa263f049924 100644
--- a/src/state_block.h
+++ b/src/state_block.h
@@ -10,13 +10,11 @@ class LocalParametrizationBase;
 
 //Wolf includes
 #include "wolf.h"
-#include "local_parametrization_base.h"
 
 //std includes
 #include <iostream>
 #include <mutex>
 
-
 namespace wolf {
 
 /** \brief class StateBlock
@@ -32,31 +30,20 @@ class StateBlock : public std::enable_shared_from_this<StateBlock>
 {
 public:
 
-  enum class Notification : std::size_t
-  {
-    ADD = 1,
-    REMOVE,
-    UPDATE_STATE,
-    UPDATE_FIX
-  };
-
-  using Notifications = std::list<Notification>;
-
     protected:
 
-        mutable Notifications notifications_;
-        mutable std::mutex notifictions_mut_;
-
-        ProblemWPtr  problem_ptr_; ///< pointer to the wolf problem
+        std::atomic_bool fixed_;                ///< Key to indicate whether the state is fixed or not
 
-        std::atomic_bool fixed_; ///< Key to indicate whether the state is fixed or not
-
-        std::atomic<SizeEigen> state_size_; ///< State vector size
-        Eigen::VectorXs state_; ///< State vector storing the state values
-        mutable std::mutex mut_state_; ///< State vector mutex
+        std::atomic<SizeEigen> state_size_;     ///< State vector size
+        Eigen::VectorXs state_;                 ///< State vector storing the state values
+        mutable std::mutex mut_state_;          ///< State vector mutex
 
         LocalParametrizationBasePtr local_param_ptr_; ///< Local parametrization useful for optimizing in the tangent space to the manifold
 
+        std::atomic_bool state_updated_;        ///< Flag to indicate whether the state has been updated or not
+        std::atomic_bool fix_updated_;          ///< Flag to indicate whether the status has been updated or not
+        std::atomic_bool local_param_updated_;  ///< Flag to indicate whether the local_parameterization has been updated or not
+
     public:
         /** \brief Constructor from size
          *
@@ -91,21 +78,11 @@ public:
          **/
         void setState(const Eigen::VectorXs& _state, const bool _notify = true);
 
-        /** \brief Set the pointer to Problem
-         */
-        void setProblem(const ProblemPtr _problem);
-
-        /** \brief Return the problem pointer
-         */
-        ProblemPtr getProblem();
-
         /** \brief Returns the state size
          **/
         SizeEigen getSize() const;
 
         /**\brief Returns the size of the local parametrization
-         *
-         * @return the size of the local parametrization
          */
         SizeEigen getLocalSize() const;
 
@@ -121,36 +98,65 @@ public:
          **/
         void unfix();
 
+        /** \brief Sets the state status
+         **/
         void setFixed(bool _fixed);
 
+        /** \brief Returns if the state has a local parametrization
+         **/
         bool hasLocalParametrization() const;
 
+        /** \brief Returns the state local parametrization ptr
+         **/
         LocalParametrizationBasePtr getLocalParametrizationPtr() const;
 
+        /** \brief Sets a local parametrization
+         **/
         void setLocalParametrizationPtr(LocalParametrizationBasePtr _local_param);
 
+        /** \brief Removes the state_block local parametrization
+         **/
         void removeLocalParametrization();
 
-        void addNotification(const StateBlock::Notification _new_notification);
+        /** \brief Return if state has been updated
+         **/
+        bool stateUpdated() const;
+
+        /** \brief Return if fix/unfix has been updated
+         **/
+        bool fixUpdated() const;
+
+        /** \brief Return if local parameterization has been updated
+         **/
+        bool localParamUpdated() const;
+
+        /** \brief Set state_updated_ to false
+         **/
+        void resetStateUpdated();
 
-        StateBlock::Notifications consumeNotifications() const;
+        /** \brief Set fix_updated_ to false
+         **/
+        void resetFixUpdated();
 
-        /** \brief Check if exist any notification
+        /** \brief Set localk_param_updated_ to false
          **/
-        bool hasNotifications() const;
+        void resetLocalParamUpdated();
 
-        /** \brief Return list of notifications
+        /** \brief Add this state_block to the problem
          **/
-        StateBlock::Notifications getNotifications() const;
+        //void addToProblem(ProblemPtr _problem_ptr);
 
+        /** \brief Remove this state_block from the problem
+         **/
+        //void removeFromProblem(ProblemPtr _problem_ptr);
 };
 
 } // namespace wolf
 
 // IMPLEMENTATION
-#include "problem.h"
 #include "local_parametrization_base.h"
 #include "node_base.h"
+#include "problem.h"
 
 namespace wolf {
 
@@ -159,7 +165,10 @@ inline StateBlock::StateBlock(const Eigen::VectorXs& _state, bool _fixed, LocalP
         fixed_(_fixed),
         state_size_(_state.size()),
         state_(_state),
-        local_param_ptr_(_local_param_ptr)
+        local_param_ptr_(_local_param_ptr),
+        state_updated_(false),
+        fix_updated_(false),
+        local_param_updated_(false)
 {
 //    std::cout << "constructed           +sb" << std::endl;
 }
@@ -169,7 +178,10 @@ inline StateBlock::StateBlock(const SizeEigen _size, bool _fixed, LocalParametri
         fixed_(_fixed),
         state_size_(_size),
         state_(Eigen::VectorXs::Zero(_size)),
-        local_param_ptr_(_local_param_ptr)
+        local_param_ptr_(_local_param_ptr),
+        state_updated_(false),
+        fix_updated_(false),
+        local_param_updated_(false)
 {
     //
 //    std::cout << "constructed           +sb" << std::endl;
@@ -227,30 +239,46 @@ inline void StateBlock::removeLocalParametrization()
 {
 	assert(local_param_ptr_ != nullptr && "state block without local parametrization");
     local_param_ptr_.reset();
+    local_param_updated_.store(true);
 }
 
 inline void StateBlock::setLocalParametrizationPtr(LocalParametrizationBasePtr _local_param)
 {
 	assert(_local_param != nullptr && "setting a null local parametrization");
     local_param_ptr_ = _local_param;
+    local_param_updated_.store(true);
 }
 
-inline void StateBlock::setProblem(const ProblemPtr _problem)
+inline bool StateBlock::stateUpdated() const
 {
-    problem_ptr_ = _problem;
+    return state_updated_.load();
 }
 
-inline ProblemPtr StateBlock::getProblem()
+inline bool StateBlock::fixUpdated() const
 {
-    return problem_ptr_.lock();
+    return fix_updated_.load();
 }
 
-inline bool StateBlock::hasNotifications() const
+inline bool StateBlock::localParamUpdated() const
 {
-  std::lock_guard<std::mutex> lock(notifictions_mut_);
-  return !notifications_.empty();
+    return local_param_updated_.load();
 }
 
-} // namespace wolf
+inline void StateBlock::resetStateUpdated()
+{
+    state_updated_.store(false);
+}
+
+inline void StateBlock::resetFixUpdated()
+{
+    fix_updated_.store(false);
+}
+
+inline void StateBlock::resetLocalParamUpdated()
+{
+    local_param_updated_.store(false);
+}
+
+}// namespace wolf
 
 #endif
diff --git a/src/test/gtest_ceres_manager.cpp b/src/test/gtest_ceres_manager.cpp
index 07ef3ab49101491c3396921f1907cb7dbe17dfb0..0df86c75e583f51f49a4dd918c79337be92a5e64 100644
--- a/src/test/gtest_ceres_manager.cpp
+++ b/src/test/gtest_ceres_manager.cpp
@@ -13,8 +13,11 @@
 #include "../state_block.h"
 #include "../capture_void.h"
 #include "../constraint_pose_2D.h"
+#include "../constraint_quaternion_absolute.h"
 #include "../solver/solver_manager.h"
 #include "../ceres_wrapper/ceres_manager.h"
+#include "../local_parametrization_angle.h"
+#include "../local_parametrization_quaternion.h"
 
 #include "ceres/ceres.h"
 
@@ -52,11 +55,28 @@ class CeresManagerWrapper : public CeresManager
             return ceres_problem_->NumParameterBlocks();
         };
 
+        int numConstraints()
+        {
+            return ceres_problem_->NumResidualBlocks();
+        };
+
         bool isConstraintRegistered(const ConstraintBasePtr& ctr_ptr) const
         {
             return ctr_2_residual_idx_.find(ctr_ptr) != ctr_2_residual_idx_.end() && ctr_2_costfunction_.find(ctr_ptr) != ctr_2_costfunction_.end();
         };
 
+        bool hasThisLocalParametrization(const StateBlockPtr& st, const LocalParametrizationBasePtr& local_param)
+        {
+            return state_blocks_local_param_.find(st) != state_blocks_local_param_.end() &&
+                   state_blocks_local_param_.at(st)->getLocalParametrizationPtr() == local_param &&
+                   ceres_problem_->GetParameterization(getAssociatedMemBlockPtr(st)) == state_blocks_local_param_.at(st).get();
+        };
+
+        bool hasLocalParametrization(const StateBlockPtr& st) const
+        {
+            return state_blocks_local_param_.find(st) != state_blocks_local_param_.end();
+        };
+
 };
 
 TEST(CeresManager, Create)
@@ -66,6 +86,9 @@ TEST(CeresManager, Create)
 
     // check double ointers to branches
     ASSERT_EQ(P, ceres_manager_ptr->getProblemPtr());
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
 }
 
 TEST(CeresManager, AddStateBlock)
@@ -86,6 +109,9 @@ TEST(CeresManager, AddStateBlock)
     // check stateblock
     ASSERT_TRUE(ceres_manager_ptr->isStateBlockRegisteredSolverManager(sb_ptr));
     ASSERT_TRUE(ceres_manager_ptr->isStateBlockRegisteredCeresManager(sb_ptr));
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
 }
 
 TEST(CeresManager, DoubleAddStateBlock)
@@ -112,6 +138,9 @@ TEST(CeresManager, DoubleAddStateBlock)
     // check stateblock
     ASSERT_TRUE(ceres_manager_ptr->isStateBlockRegisteredSolverManager(sb_ptr));
     ASSERT_TRUE(ceres_manager_ptr->isStateBlockRegisteredCeresManager(sb_ptr));
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
 }
 
 TEST(CeresManager, UpdateStateBlock)
@@ -140,6 +169,9 @@ TEST(CeresManager, UpdateStateBlock)
 
     // check stateblock fixed
     ASSERT_TRUE(ceres_manager_ptr->isStateBlockFixed(sb_ptr));
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
 }
 
 TEST(CeresManager, AddUpdateStateBlock)
@@ -164,6 +196,9 @@ TEST(CeresManager, AddUpdateStateBlock)
     ASSERT_TRUE(ceres_manager_ptr->isStateBlockRegisteredSolverManager(sb_ptr));
     ASSERT_TRUE(ceres_manager_ptr->isStateBlockRegisteredCeresManager(sb_ptr));
     ASSERT_TRUE(ceres_manager_ptr->isStateBlockFixed(sb_ptr));
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
 }
 
 TEST(CeresManager, RemoveStateBlock)
@@ -185,14 +220,17 @@ TEST(CeresManager, RemoveStateBlock)
     ASSERT_TRUE(ceres_manager_ptr->isStateBlockRegisteredCeresManager(sb_ptr));
 
     // remove state_block
-    P->removeStateBlockPtr(sb_ptr);
+    P->removeStateBlock(sb_ptr);
 
     // update solver
     ceres_manager_ptr->update();
 
     // check stateblock
     ASSERT_FALSE(ceres_manager_ptr->isStateBlockRegisteredSolverManager(sb_ptr));
-    ASSERT_TRUE(ceres_manager_ptr->numStateBlocks() == 0);
+    ASSERT_EQ(ceres_manager_ptr->numStateBlocks(), 0);
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
 }
 
 TEST(CeresManager, AddRemoveStateBlock)
@@ -208,14 +246,17 @@ TEST(CeresManager, AddRemoveStateBlock)
     P->addStateBlock(sb_ptr);
 
     // remove state_block
-    P->removeStateBlockPtr(sb_ptr);
+    P->removeStateBlock(sb_ptr);
 
     // update solver
     ceres_manager_ptr->update();
 
     // check no stateblocks
     ASSERT_FALSE(ceres_manager_ptr->isStateBlockRegisteredSolverManager(sb_ptr));
-    ASSERT_TRUE(ceres_manager_ptr->numStateBlocks() == 0);
+    ASSERT_EQ(ceres_manager_ptr->numStateBlocks(), 0);
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
 }
 
 TEST(CeresManager, RemoveUpdateStateBlock)
@@ -234,10 +275,13 @@ TEST(CeresManager, RemoveUpdateStateBlock)
     ceres_manager_ptr->update();
 
     // remove state_block
-    P->removeStateBlockPtr(sb_ptr);
+    P->removeStateBlock(sb_ptr);
 
     // update solver
     ceres_manager_ptr->update();
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
 }
 
 TEST(CeresManager, DoubleRemoveStateBlock)
@@ -253,16 +297,19 @@ TEST(CeresManager, DoubleRemoveStateBlock)
     P->addStateBlock(sb_ptr);
 
     // remove state_block
-    P->removeStateBlockPtr(sb_ptr);
+    P->removeStateBlock(sb_ptr);
 
     // update solver
     ceres_manager_ptr->update();
 
     // remove state_block
-    P->removeStateBlockPtr(sb_ptr);
+    P->removeStateBlock(sb_ptr);
 
     // update solver manager
     ceres_manager_ptr->update();
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
 }
 
 TEST(CeresManager, AddConstraint)
@@ -270,9 +317,27 @@ TEST(CeresManager, AddConstraint)
     ProblemPtr P = Problem::create("PO 2D");
     CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P);
 
-    // Create State block
-    Vector2s state; state << 1, 2;
-    StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state);
+    // Create (and add) constraint point 2d
+    FrameBasePtr        F = P->emplaceFrame(KEY_FRAME, P->zeroState(), TimeStamp(0));
+    CaptureBasePtr      C = F->addCapture(std::make_shared<CaptureVoid>(0, nullptr));
+    FeatureBasePtr      f = C->addFeature(std::make_shared<FeatureBase>("ODOM 2D", Vector3s::Zero(), Matrix3s::Identity()));
+    ConstraintPose2DPtr c = std::static_pointer_cast<ConstraintPose2D>(f->addConstraint(std::make_shared<ConstraintPose2D>(f)));
+
+    // update solver
+    ceres_manager_ptr->update();
+
+    // check constraint
+    ASSERT_TRUE(ceres_manager_ptr->isConstraintRegistered(c));
+    ASSERT_EQ(ceres_manager_ptr->numConstraints(), 1);
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
+}
+
+TEST(CeresManager, DoubleAddConstraint)
+{
+    ProblemPtr P = Problem::create("PO 2D");
+    CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P);
 
     // Create (and add) constraint point 2d
     FrameBasePtr        F = P->emplaceFrame(KEY_FRAME, P->zeroState(), TimeStamp(0));
@@ -280,11 +345,18 @@ TEST(CeresManager, AddConstraint)
     FeatureBasePtr      f = C->addFeature(std::make_shared<FeatureBase>("ODOM 2D", Vector3s::Zero(), Matrix3s::Identity()));
     ConstraintPose2DPtr c = std::static_pointer_cast<ConstraintPose2D>(f->addConstraint(std::make_shared<ConstraintPose2D>(f)));
 
+    // add constraint again
+    P->addConstraint(c);
+
     // update solver
     ceres_manager_ptr->update();
 
     // check constraint
     ASSERT_TRUE(ceres_manager_ptr->isConstraintRegistered(c));
+    ASSERT_EQ(ceres_manager_ptr->numConstraints(), 1);
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
 }
 
 TEST(CeresManager, RemoveConstraint)
@@ -292,10 +364,6 @@ TEST(CeresManager, RemoveConstraint)
     ProblemPtr P = Problem::create("PO 2D");
     CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P);
 
-    // Create State block
-    Vector2s state; state << 1, 2;
-    StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state);
-
     // Create (and add) constraint point 2d
     FrameBasePtr        F = P->emplaceFrame(KEY_FRAME, P->zeroState(), TimeStamp(0));
     CaptureBasePtr      C = F->addCapture(std::make_shared<CaptureVoid>(0, nullptr));
@@ -305,14 +373,18 @@ TEST(CeresManager, RemoveConstraint)
     // update solver
     ceres_manager_ptr->update();
 
-    // add constraint
-    P->removeConstraintPtr(c);
+    // remove constraint
+    P->removeConstraint(c);
 
     // update solver
     ceres_manager_ptr->update();
 
     // check constraint
     ASSERT_FALSE(ceres_manager_ptr->isConstraintRegistered(c));
+    ASSERT_EQ(ceres_manager_ptr->numConstraints(), 0);
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
 }
 
 TEST(CeresManager, AddRemoveConstraint)
@@ -320,28 +392,28 @@ TEST(CeresManager, AddRemoveConstraint)
     ProblemPtr P = Problem::create("PO 2D");
     CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P);
 
-    // Create State block
-    Vector2s state; state << 1, 2;
-    StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state);
-
     // Create (and add) constraint point 2d
     FrameBasePtr        F = P->emplaceFrame(KEY_FRAME, P->zeroState(), TimeStamp(0));
     CaptureBasePtr      C = F->addCapture(std::make_shared<CaptureVoid>(0, nullptr));
     FeatureBasePtr      f = C->addFeature(std::make_shared<FeatureBase>("ODOM 2D", Vector3s::Zero(), Matrix3s::Identity()));
     ConstraintPose2DPtr c = std::static_pointer_cast<ConstraintPose2D>(f->addConstraint(std::make_shared<ConstraintPose2D>(f)));
 
-    ASSERT_TRUE(P->getConstraintNotificationList().front().constraint_ptr_ == c);
+    ASSERT_TRUE(P->getConstraintNotificationMap().begin()->first == c);
 
-    // add constraint
-    P->removeConstraintPtr(c);
+    // remove constraint
+    P->removeConstraint(c);
 
-    ASSERT_TRUE(P->getConstraintNotificationList().empty());
+    ASSERT_TRUE(P->getConstraintNotificationMap().empty());
 
     // update solver
     ceres_manager_ptr->update();
 
     // check constraint
     ASSERT_FALSE(ceres_manager_ptr->isConstraintRegistered(c));
+    ASSERT_EQ(ceres_manager_ptr->numConstraints(), 0);
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
 }
 
 TEST(CeresManager, DoubleRemoveConstraint)
@@ -349,10 +421,6 @@ TEST(CeresManager, DoubleRemoveConstraint)
     ProblemPtr P = Problem::create("PO 2D");
     CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P);
 
-    // Create State block
-    Vector2s state; state << 1, 2;
-    StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state);
-
     // Create (and add) constraint point 2d
     FrameBasePtr        F = P->emplaceFrame(KEY_FRAME, P->zeroState(), TimeStamp(0));
     CaptureBasePtr      C = F->addCapture(std::make_shared<CaptureVoid>(0, nullptr));
@@ -363,13 +431,13 @@ TEST(CeresManager, DoubleRemoveConstraint)
     ceres_manager_ptr->update();
 
     // remove constraint
-    P->removeConstraintPtr(c);
+    P->removeConstraint(c);
 
     // update solver
     ceres_manager_ptr->update();
 
     // remove constraint
-    P->removeConstraintPtr(c);
+    P->removeConstraint(c);
 
     ASSERT_DEATH({
     // update solver
@@ -377,8 +445,191 @@ TEST(CeresManager, DoubleRemoveConstraint)
 
     // check constraint
     ASSERT_FALSE(ceres_manager_ptr->isConstraintRegistered(c));
+    ASSERT_EQ(ceres_manager_ptr->numConstraints(), 0);
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
+}
+
+TEST(CeresManager, AddStateBlockLocalParam)
+{
+    ProblemPtr P = Problem::create("PO 2D");
+    CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P);
+
+    // Create State block
+    Vector1s state; state << 1;
+    StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state);
+
+    // Local param
+    LocalParametrizationBasePtr local_param_ptr = std::make_shared<LocalParametrizationAngle>();
+    sb_ptr->setLocalParametrizationPtr(local_param_ptr);
+
+    // add stateblock
+    P->addStateBlock(sb_ptr);
+
+    // update solver
+    ceres_manager_ptr->update();
+
+    // check stateblock
+    ASSERT_TRUE(ceres_manager_ptr->hasLocalParametrization(sb_ptr));
+    ASSERT_TRUE(ceres_manager_ptr->hasThisLocalParametrization(sb_ptr,local_param_ptr));
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
 }
 
+TEST(CeresManager, RemoveLocalParam)
+{
+    ProblemPtr P = Problem::create("PO 2D");
+    CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P);
+
+    // Create State block
+    Vector1s state; state << 1;
+    StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state);
+
+    // Local param
+    LocalParametrizationBasePtr local_param_ptr = std::make_shared<LocalParametrizationAngle>();
+    sb_ptr->setLocalParametrizationPtr(local_param_ptr);
+
+    // add stateblock
+    P->addStateBlock(sb_ptr);
+
+    // update solver
+    ceres_manager_ptr->update();
+
+    // Remove local param
+    sb_ptr->removeLocalParametrization();
+
+    // update solver
+    ceres_manager_ptr->update();
+
+    // check stateblock
+    ASSERT_FALSE(ceres_manager_ptr->hasLocalParametrization(sb_ptr));
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
+}
+
+TEST(CeresManager, AddLocalParam)
+{
+    ProblemPtr P = Problem::create("PO 2D");
+    CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P);
+
+    // Create State block
+    Vector1s state; state << 1;
+    StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state);
+
+    // add stateblock
+    P->addStateBlock(sb_ptr);
+
+    // update solver
+    ceres_manager_ptr->update();
+
+    // check stateblock
+    ASSERT_FALSE(ceres_manager_ptr->hasLocalParametrization(sb_ptr));
+
+    // Local param
+    LocalParametrizationBasePtr local_param_ptr = std::make_shared<LocalParametrizationAngle>();
+    sb_ptr->setLocalParametrizationPtr(local_param_ptr);
+
+    // update solver
+    ceres_manager_ptr->update();
+
+    // check stateblock
+    ASSERT_TRUE(ceres_manager_ptr->hasLocalParametrization(sb_ptr));
+    ASSERT_TRUE(ceres_manager_ptr->hasThisLocalParametrization(sb_ptr,local_param_ptr));
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
+}
+
+TEST(CeresManager, ConstraintsRemoveLocalParam)
+{
+    ProblemPtr P = Problem::create("PO 3D");
+    CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P);
+
+    // Create (and add) 2 constraints quaternion
+    FrameBasePtr                    F = P->emplaceFrame(KEY_FRAME, P->zeroState(), TimeStamp(0));
+    CaptureBasePtr                  C = F->addCapture(std::make_shared<CaptureVoid>(0, nullptr));
+    FeatureBasePtr                  f = C->addFeature(std::make_shared<FeatureBase>("ODOM 2D", Vector3s::Zero(), Matrix3s::Identity()));
+    ConstraintQuaternionAbsolutePtr c1 = std::static_pointer_cast<ConstraintQuaternionAbsolute>(f->addConstraint(std::make_shared<ConstraintQuaternionAbsolute>(F->getOPtr())));
+    ConstraintQuaternionAbsolutePtr c2 = std::static_pointer_cast<ConstraintQuaternionAbsolute>(f->addConstraint(std::make_shared<ConstraintQuaternionAbsolute>(F->getOPtr())));
+
+    // update solver
+    ceres_manager_ptr->update();
+
+    // check local param
+    ASSERT_TRUE(ceres_manager_ptr->hasLocalParametrization(F->getOPtr()));
+    ASSERT_TRUE(ceres_manager_ptr->hasThisLocalParametrization(F->getOPtr(),F->getOPtr()->getLocalParametrizationPtr()));
+
+    // check constraint
+    ASSERT_TRUE(ceres_manager_ptr->isConstraintRegistered(c1));
+    ASSERT_TRUE(ceres_manager_ptr->isConstraintRegistered(c2));
+    ASSERT_EQ(ceres_manager_ptr->numConstraints(), 2);
+
+    // remove local param
+    F->getOPtr()->removeLocalParametrization();
+
+    // update solver
+    ceres_manager_ptr->update();
+
+    // check local param
+    ASSERT_FALSE(ceres_manager_ptr->hasLocalParametrization(F->getOPtr()));
+
+    // check constraint
+    ASSERT_TRUE(ceres_manager_ptr->isConstraintRegistered(c1));
+    ASSERT_TRUE(ceres_manager_ptr->isConstraintRegistered(c2));
+    ASSERT_EQ(ceres_manager_ptr->numConstraints(), 2);
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
+}
+
+TEST(CeresManager, ConstraintsUpdateLocalParam)
+{
+    ProblemPtr P = Problem::create("PO 3D");
+    CeresManagerWrapperPtr ceres_manager_ptr = std::make_shared<CeresManagerWrapper>(P);
+
+    // Create (and add) 2 constraints quaternion
+    FrameBasePtr                    F = P->emplaceFrame(KEY_FRAME, P->zeroState(), TimeStamp(0));
+    CaptureBasePtr                  C = F->addCapture(std::make_shared<CaptureVoid>(0, nullptr));
+    FeatureBasePtr                  f = C->addFeature(std::make_shared<FeatureBase>("ODOM 2D", Vector3s::Zero(), Matrix3s::Identity()));
+    ConstraintQuaternionAbsolutePtr c1 = std::static_pointer_cast<ConstraintQuaternionAbsolute>(f->addConstraint(std::make_shared<ConstraintQuaternionAbsolute>(F->getOPtr())));
+    ConstraintQuaternionAbsolutePtr c2 = std::static_pointer_cast<ConstraintQuaternionAbsolute>(f->addConstraint(std::make_shared<ConstraintQuaternionAbsolute>(F->getOPtr())));
+
+    // update solver
+    ceres_manager_ptr->update();
+
+    // check local param
+    ASSERT_TRUE(ceres_manager_ptr->hasLocalParametrization(F->getOPtr()));
+    ASSERT_TRUE(ceres_manager_ptr->hasThisLocalParametrization(F->getOPtr(),F->getOPtr()->getLocalParametrizationPtr()));
+
+    // check constraint
+    ASSERT_TRUE(ceres_manager_ptr->isConstraintRegistered(c1));
+    ASSERT_TRUE(ceres_manager_ptr->isConstraintRegistered(c2));
+    ASSERT_EQ(ceres_manager_ptr->numConstraints(), 2);
+
+    // remove local param
+    LocalParametrizationBasePtr local_param_ptr = std::make_shared<LocalParametrizationQuaternionGlobal>();
+    F->getOPtr()->setLocalParametrizationPtr(local_param_ptr);
+
+    // update solver
+    ceres_manager_ptr->update();
+
+    // check local param
+    ASSERT_TRUE(ceres_manager_ptr->hasLocalParametrization(F->getOPtr()));
+    ASSERT_TRUE(ceres_manager_ptr->hasThisLocalParametrization(F->getOPtr(),local_param_ptr));
+
+    // check constraint
+    ASSERT_TRUE(ceres_manager_ptr->isConstraintRegistered(c1));
+    ASSERT_TRUE(ceres_manager_ptr->isConstraintRegistered(c2));
+    ASSERT_EQ(ceres_manager_ptr->numConstraints(), 2);
+
+    // run ceres manager check
+    ceres_manager_ptr->check();
+}
+
+
 int main(int argc, char **argv)
 {
   testing::InitGoogleTest(&argc, argv);
diff --git a/src/test/gtest_problem.cpp b/src/test/gtest_problem.cpp
index 9ab18d070e75c5f9e4a01f7434dc192ce7c84595..7ae62578b7d99441e56539a94830696e6489253c 100644
--- a/src/test/gtest_problem.cpp
+++ b/src/test/gtest_problem.cpp
@@ -214,12 +214,12 @@ TEST(Problem, StateBlocks)
     // 2 state blocks, fixed
     SensorBasePtr    Sm = P->installSensor   ("ODOM 3D", "odometer",xs, wolf_root + "/src/examples/sensor_odom_3D.yaml");
     ASSERT_EQ(P->getStateBlockList().size(), (unsigned int) 2);
-    ASSERT_EQ(P->getNotifiedStateBlockList().size(), (unsigned int) 2);
+    ASSERT_EQ(P->getStateBlockNotificationMap().size(), (unsigned int) 2);
 
     // 3 state blocks, fixed
     SensorBasePtr    St = P->installSensor   ("CAMERA", "camera",   xs, wolf_root + "/src/examples/camera_params_ueye_sim.yaml");
     ASSERT_EQ(P->getStateBlockList().size(), (unsigned int) (2 + 3));
-    ASSERT_EQ(P->getNotifiedStateBlockList().size(), (unsigned int) (2 + 3));
+    ASSERT_EQ(P->getStateBlockNotificationMap().size(), (unsigned int) (2 + 3));
 
     ProcessorParamsTrackerFeaturePtr params = std::make_shared<ProcessorParamsTrackerFeature>();
     params->time_tolerance            = 0.1;
@@ -233,7 +233,7 @@ TEST(Problem, StateBlocks)
     // 2 state blocks, estimated
     P->emplaceFrame("PO 3D", KEY_FRAME, xs, 0);
     ASSERT_EQ(P->getStateBlockList().size(), (unsigned int)(2 + 3 + 2));
-    ASSERT_EQ(P->getNotifiedStateBlockList().size(), (unsigned int)(2 + 3 + 2));
+    ASSERT_EQ(P->getStateBlockNotificationMap().size(), (unsigned int)(2 + 3 + 2));
 
 
     //    P->print(4,1,1,1);
@@ -241,7 +241,7 @@ TEST(Problem, StateBlocks)
     // change some SB properties
     St->unfixExtrinsics();
     ASSERT_EQ(P->getStateBlockList().size(), (unsigned int)(2 + 3 + 2));
-    ASSERT_EQ(P->getNotifiedStateBlockList().size(),(unsigned int)(2 + 3 + 2 /*+ 2*/)); // XXX: 2 more notifications on the same SB!
+    ASSERT_EQ(P->getStateBlockNotificationMap().size(),(unsigned int)(2 + 3 + 2 /*+ 2*/)); // XXX: 2 more notifications on the same SB!
 
     //    P->print(4,1,1,1);
 }
diff --git a/src/test/gtest_solver_manager.cpp b/src/test/gtest_solver_manager.cpp
index f2aee334e543ab02507c302d44a010555a70e4f1..effdfc1401c6ece1822651f287dfb7d4ffb1bbb3 100644
--- a/src/test/gtest_solver_manager.cpp
+++ b/src/test/gtest_solver_manager.cpp
@@ -14,6 +14,8 @@
 #include "../capture_void.h"
 #include "../constraint_pose_2D.h"
 #include "../solver/solver_manager.h"
+#include "../local_parametrization_base.h"
+#include "../local_parametrization_angle.h"
 
 #include <iostream>
 
@@ -26,6 +28,7 @@ class SolverManagerWrapper : public SolverManager
     public:
         std::list<ConstraintBasePtr> constraints_;
         std::map<StateBlockPtr,bool> state_block_fixed_;
+        std::map<StateBlockPtr,LocalParametrizationBasePtr> state_block_local_param_;
 
         SolverManagerWrapper(const ProblemPtr& wolf_problem) :
             SolverManager(wolf_problem)
@@ -47,6 +50,16 @@ class SolverManagerWrapper : public SolverManager
             return std::find(constraints_.begin(), constraints_.end(), ctr_ptr) != constraints_.end();
         };
 
+        bool hasThisLocalParametrization(const StateBlockPtr& st, const LocalParametrizationBasePtr& local_param) const
+        {
+            return state_block_local_param_.find(st) != state_block_local_param_.end() && state_block_local_param_.at(st) == local_param;
+        };
+
+        bool hasLocalParametrization(const StateBlockPtr& st) const
+        {
+            return state_block_local_param_.find(st) != state_block_local_param_.end();
+        };
+
         virtual void computeCovariances(const CovarianceBlocksToBeComputed blocks){};
         virtual void computeCovariances(const StateBlockList& st_list){};
 
@@ -64,15 +77,24 @@ class SolverManagerWrapper : public SolverManager
         virtual void addStateBlock(const StateBlockPtr& state_ptr)
         {
             state_block_fixed_[state_ptr] = state_ptr->isFixed();
+            state_block_local_param_[state_ptr] = state_ptr->getLocalParametrizationPtr();
         };
         virtual void removeStateBlock(const StateBlockPtr& state_ptr)
         {
             state_block_fixed_.erase(state_ptr);
+            state_block_local_param_.erase(state_ptr);
         };
         virtual void updateStateBlockStatus(const StateBlockPtr& state_ptr)
         {
             state_block_fixed_[state_ptr] = state_ptr->isFixed();
         };
+        virtual void updateStateBlockLocalParametrization(const StateBlockPtr& state_ptr)
+        {
+            if (state_ptr->getLocalParametrizationPtr() == nullptr)
+                state_block_local_param_.erase(state_ptr);
+            else
+                state_block_local_param_[state_ptr] = state_ptr->getLocalParametrizationPtr();
+        };
 };
 
 TEST(SolverManager, Create)
@@ -140,18 +162,38 @@ TEST(SolverManager, UpdateStateBlock)
     // add stateblock
     P->addStateBlock(sb_ptr);
 
+    // check flags
+    ASSERT_FALSE(sb_ptr->stateUpdated());
+    ASSERT_FALSE(sb_ptr->fixUpdated());
+    ASSERT_FALSE(sb_ptr->localParamUpdated());
+
     // update solver
     solver_manager_ptr->update();
 
+    // check flags
+    ASSERT_FALSE(sb_ptr->stateUpdated());
+    ASSERT_FALSE(sb_ptr->fixUpdated());
+    ASSERT_FALSE(sb_ptr->localParamUpdated());
+
     // check stateblock unfixed
     ASSERT_FALSE(solver_manager_ptr->isStateBlockFixed(sb_ptr));
 
     // Fix frame
     sb_ptr->fix();
 
+    // check flags
+    ASSERT_FALSE(sb_ptr->stateUpdated());
+    ASSERT_TRUE(sb_ptr->fixUpdated());
+    ASSERT_FALSE(sb_ptr->localParamUpdated());
+
     // update solver manager
     solver_manager_ptr->update();
 
+    // check flags
+    ASSERT_FALSE(sb_ptr->stateUpdated());
+    ASSERT_FALSE(sb_ptr->fixUpdated());
+    ASSERT_FALSE(sb_ptr->localParamUpdated());
+
     // check stateblock fixed
     ASSERT_TRUE(solver_manager_ptr->isStateBlockFixed(sb_ptr));
 }
@@ -168,15 +210,120 @@ TEST(SolverManager, AddUpdateStateBlock)
     // add stateblock
     P->addStateBlock(sb_ptr);
 
+    // check flags
+    ASSERT_FALSE(sb_ptr->stateUpdated());
+    ASSERT_FALSE(sb_ptr->fixUpdated());
+    ASSERT_FALSE(sb_ptr->localParamUpdated());
+
     // Fix state block
     sb_ptr->fix();
 
+    // check flags
+    ASSERT_FALSE(sb_ptr->stateUpdated());
+    ASSERT_TRUE(sb_ptr->fixUpdated());
+    ASSERT_FALSE(sb_ptr->localParamUpdated());
+
     // update solver manager
     solver_manager_ptr->update();
 
+    // check flags
+    ASSERT_FALSE(sb_ptr->stateUpdated());
+    ASSERT_FALSE(sb_ptr->fixUpdated());
+    ASSERT_FALSE(sb_ptr->localParamUpdated());
+
+    // check stateblock fixed
+    ASSERT_TRUE(solver_manager_ptr->isStateBlockRegistered(sb_ptr));
+    ASSERT_TRUE(solver_manager_ptr->isStateBlockFixed(sb_ptr));
+}
+
+TEST(SolverManager, AddUpdateLocalParamStateBlock)
+{
+    ProblemPtr P = Problem::create("PO 2D");
+    SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P);
+
+    // Create State block
+    Vector2s state; state << 1, 2;
+    StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state);
+
+    // add stateblock
+    P->addStateBlock(sb_ptr);
+
+    // check flags
+    ASSERT_FALSE(sb_ptr->stateUpdated());
+    ASSERT_FALSE(sb_ptr->fixUpdated());
+    ASSERT_FALSE(sb_ptr->localParamUpdated());
+
+    // Local param
+    LocalParametrizationBasePtr local_ptr = std::make_shared<LocalParametrizationAngle>();
+    sb_ptr->setLocalParametrizationPtr(local_ptr);
+
+    // Fix state block
+    sb_ptr->fix();
+
+    // check flags
+    ASSERT_FALSE(sb_ptr->stateUpdated());
+    ASSERT_TRUE(sb_ptr->fixUpdated());
+    ASSERT_TRUE(sb_ptr->localParamUpdated());
+
+    // update solver manager
+    solver_manager_ptr->update();
+
+    // check flags
+    ASSERT_FALSE(sb_ptr->stateUpdated());
+    ASSERT_FALSE(sb_ptr->fixUpdated());
+    ASSERT_FALSE(sb_ptr->localParamUpdated());
+
     // check stateblock fixed
     ASSERT_TRUE(solver_manager_ptr->isStateBlockRegistered(sb_ptr));
     ASSERT_TRUE(solver_manager_ptr->isStateBlockFixed(sb_ptr));
+    ASSERT_TRUE(solver_manager_ptr->hasThisLocalParametrization(sb_ptr,local_ptr));
+}
+
+TEST(SolverManager, AddLocalParamRemoveLocalParamStateBlock)
+{
+    ProblemPtr P = Problem::create("PO 2D");
+    SolverManagerWrapperPtr solver_manager_ptr = std::make_shared<SolverManagerWrapper>(P);
+
+    // Create State block
+    Vector2s state; state << 1, 2;
+    StateBlockPtr sb_ptr = std::make_shared<StateBlock>(state);
+
+    // Local param
+    LocalParametrizationBasePtr local_ptr = std::make_shared<LocalParametrizationAngle>();
+    sb_ptr->setLocalParametrizationPtr(local_ptr);
+
+    // check flags
+    ASSERT_FALSE(sb_ptr->stateUpdated());
+    ASSERT_FALSE(sb_ptr->fixUpdated());
+    ASSERT_TRUE(sb_ptr->localParamUpdated());
+
+    // add stateblock
+    P->addStateBlock(sb_ptr);
+
+    // update solver manager
+    solver_manager_ptr->update();
+
+    // check stateblock localparam
+    ASSERT_TRUE(solver_manager_ptr->hasThisLocalParametrization(sb_ptr,local_ptr));
+
+    // check flags
+    ASSERT_FALSE(sb_ptr->stateUpdated());
+    ASSERT_FALSE(sb_ptr->fixUpdated());
+    ASSERT_FALSE(sb_ptr->localParamUpdated());
+
+    // Remove local param
+    sb_ptr->removeLocalParametrization();
+
+    // check flags
+    ASSERT_FALSE(sb_ptr->stateUpdated());
+    ASSERT_FALSE(sb_ptr->fixUpdated());
+    ASSERT_TRUE(sb_ptr->localParamUpdated());
+
+    // update solver manager
+    solver_manager_ptr->update();
+
+    // check stateblock localparam
+    ASSERT_FALSE(solver_manager_ptr->hasLocalParametrization(sb_ptr));
 }
 
 TEST(SolverManager, RemoveStateBlock)
@@ -195,7 +342,7 @@ TEST(SolverManager, RemoveStateBlock)
     solver_manager_ptr->update();
 
     // remove state_block
-    P->removeStateBlockPtr(sb_ptr);
+    P->removeStateBlock(sb_ptr);
 
     // update solver
     solver_manager_ptr->update();
@@ -217,7 +364,7 @@ TEST(SolverManager, AddRemoveStateBlock)
     P->addStateBlock(sb_ptr);
 
     // remove state_block
-    P->removeStateBlockPtr(sb_ptr);
+    P->removeStateBlock(sb_ptr);
 
     // update solver
     solver_manager_ptr->update();
@@ -239,7 +386,7 @@ TEST(SolverManager, RemoveUpdateStateBlock)
     P->addStateBlock(sb_ptr);
 
     // remove state_block
-    P->removeStateBlockPtr(sb_ptr);
+    P->removeStateBlock(sb_ptr);
 
     // update solver
     solver_manager_ptr->update();
@@ -258,13 +405,13 @@ TEST(SolverManager, DoubleRemoveStateBlock)
     P->addStateBlock(sb_ptr);
 
     // remove state_block
-    P->removeStateBlockPtr(sb_ptr);
+    P->removeStateBlock(sb_ptr);
 
     // update solver
     solver_manager_ptr->update();
 
     // remove state_block
-    P->removeStateBlockPtr(sb_ptr);
+    P->removeStateBlock(sb_ptr);
 
     // update solver manager
     solver_manager_ptr->update();
@@ -286,65 +433,46 @@ TEST(SolverManager, AddUpdatedStateBlock)
     Vector2s state_2 = 2*state;
     sb_ptr->setState(state_2);
 
-    // == First add 2 UPDATES (FIX and STATE) ==
-
-    // The expected order is:
-    // ADD in front of the list
-    // Others in historical order
-    ASSERT_EQ(sb_ptr->getNotifications().size(),2); // UPDATE_FIX, UPDATE_STATE
-    StateBlock::Notifications sb_notif = sb_ptr->getNotifications();
-    StateBlock::Notifications::iterator iter = sb_notif.begin();
-    ASSERT_EQ(*iter,StateBlock::Notification::UPDATE_FIX);
-    iter++;
-    ASSERT_EQ(*iter,StateBlock::Notification::UPDATE_STATE);
+    // Check flags have been set true
+    ASSERT_TRUE(sb_ptr->fixUpdated());
+    ASSERT_TRUE(sb_ptr->stateUpdated());
 
     // == When an ADD is notified, all previous notifications should be cleared (if not consumption of notifs) ==
 
     // add state_block
     P->addStateBlock(sb_ptr);
 
-    // Get list of SB notifications
-    StateBlockList P_notif_sb = P->getNotifiedStateBlockList();
-
-    ASSERT_EQ(P_notif_sb.size(),1);
-
-    sb_notif = P_notif_sb.front()->getNotifications();
-
-    ASSERT_EQ(sb_notif.size(),1);
-    ASSERT_EQ(sb_notif.front(),StateBlock::Notification::ADD);
+    ASSERT_EQ(P->getStateBlockNotificationMap().size(),1);
+    ASSERT_EQ(P->getStateBlockNotificationMap().begin()->second,ADD);
 
     // == Insert OTHER notifications ==
 
-    // Set State
+    // Set State --> FLAG
     state_2 = 2*state;
     sb_ptr->setState(state_2);
 
-    // Fix
+    // Fix --> FLAG
     sb_ptr->unfix();
 
-    sb_notif = P_notif_sb.front()->getNotifications();
-    ASSERT_EQ(sb_notif.size(),3); // ADD, UPDATE_STATE, UPDATE_FIX
-
-    iter = sb_notif.begin();
-    ASSERT_EQ(*iter,StateBlock::Notification::ADD);
-    iter++;
-    ASSERT_EQ(*iter,StateBlock::Notification::UPDATE_STATE);
-    iter++;
-    ASSERT_EQ(*iter,StateBlock::Notification::UPDATE_FIX);
+    ASSERT_EQ(P->getStateBlockNotificationMap().size(),1); // only ADD notification (fix and state are flags in sb)
 
-    // == REMOVE should clear all previous notifications in the stack because there's an ADD ==
+    // == REMOVE should clear the previous notification (ADD) in the stack ==
 
     // remove state_block
-    P->removeStateBlockPtr(sb_ptr);
-
-    P_notif_sb = P->getNotifiedStateBlockList();
-    ASSERT_EQ(P_notif_sb.size(),1);
+    P->removeStateBlock(sb_ptr);
 
-    sb_notif = P_notif_sb.front()->getNotifications();
-    ASSERT_EQ(sb_notif.size(),0); // ADD + REMOVE = EMPTY
+    ASSERT_EQ(P->getStateBlockNotificationMap().size(),0);// ADD + REMOVE = EMPTY
 
     // == UPDATES + REMOVE should clear the list of notifications ==
 
+    // add state_block
+    P->addStateBlock(sb_ptr);
+
+    // update solver
+    solver_manager_ptr->update();
+
+    ASSERT_EQ(P->getStateBlockNotificationMap().size(),0); // After solver_manager->update, notifications should be empty
+
     // Fix
     sb_ptr->fix();
 
@@ -353,11 +481,10 @@ TEST(SolverManager, AddUpdatedStateBlock)
     sb_ptr->setState(state_2);
 
     // remove state_block
-    P->removeStateBlockPtr(sb_ptr);
+    P->removeStateBlock(sb_ptr);
 
-    sb_notif = P_notif_sb.front()->getNotifications();
-    ASSERT_EQ(sb_notif.size(),1);
-    ASSERT_EQ(sb_notif.front(),StateBlock::Notification::REMOVE);
+    ASSERT_EQ(P->getStateBlockNotificationMap().size(),1);
+    ASSERT_EQ(P->getStateBlockNotificationMap().begin()->second, REMOVE);
 }
 
 TEST(SolverManager, AddConstraint)
@@ -401,7 +528,7 @@ TEST(SolverManager, RemoveConstraint)
     solver_manager_ptr->update();
 
     // add constraint
-    P->removeConstraintPtr(c);
+    P->removeConstraint(c);
 
     // update solver
     solver_manager_ptr->update();
@@ -425,12 +552,12 @@ TEST(SolverManager, AddRemoveConstraint)
     FeatureBasePtr      f = C->addFeature(std::make_shared<FeatureBase>("ODOM 2D", Vector3s::Zero(), Matrix3s::Identity()));
     ConstraintPose2DPtr c = std::static_pointer_cast<ConstraintPose2D>(f->addConstraint(std::make_shared<ConstraintPose2D>(f)));
 
-    ASSERT_TRUE(P->getConstraintNotificationList().front().constraint_ptr_ == c);
+    ASSERT_TRUE(P->getConstraintNotificationMap().begin()->first == c);
 
     // add constraint
-    P->removeConstraintPtr(c);
+    P->removeConstraint(c);
 
-    ASSERT_TRUE(P->getConstraintNotificationList().empty());
+    ASSERT_TRUE(P->getConstraintNotificationMap().empty());
 
     // update solver
     solver_manager_ptr->update();
@@ -458,13 +585,13 @@ TEST(SolverManager, DoubleRemoveConstraint)
     solver_manager_ptr->update();
 
     // remove constraint
-    P->removeConstraintPtr(c);
+    P->removeConstraint(c);
 
     // update solver
     solver_manager_ptr->update();
 
     // remove constraint
-    P->removeConstraintPtr(c);
+    P->removeConstraint(c);
 
     // update solver
     solver_manager_ptr->update();
diff --git a/src/test/gtest_trajectory.cpp b/src/test/gtest_trajectory.cpp
index 17e0667475716d16b694ee8c2b3d8139e91035af..92c8480399d9bdd77038672f48465e2d93294f5c 100644
--- a/src/test/gtest_trajectory.cpp
+++ b/src/test/gtest_trajectory.cpp
@@ -32,42 +32,25 @@ struct DummyNotificationProcessor
       FAIL() << "problem_ is nullptr !";
     }
 
-    StateBlockList& states = problem_->getNotifiedStateBlockList();
-
-    for (StateBlockPtr& state : states)
+    auto sb_noti_pair = problem_->getStateBlockNotificationMap().begin();
+    while (sb_noti_pair != problem_->getStateBlockNotificationMap().end())
     {
-      const auto notifications = state->consumeNotifications();
-
-      for (const auto notif : notifications)
-      {
-        switch (notif)
+        switch (sb_noti_pair->second)
         {
-          case StateBlock::Notification::ADD:
-          {
-            break;
-          }
-          case StateBlock::Notification::UPDATE_STATE:
+          case ADD:
           {
             break;
           }
-          case StateBlock::Notification::UPDATE_FIX:
-          {
-            break;
-          }
-          case StateBlock::Notification::REMOVE:
+          case REMOVE:
           {
             break;
           }
           default:
-            throw std::runtime_error("SolverManager::update: State Block notification "
-                                     "must be ADD, STATE_UPDATE, FIX_UPDATE, REMOVE or ENABLED.");
+            throw std::runtime_error("SolverManager::update: State Block notification must be ADD or REMOVE.");
         }
-      }
-
-      ASSERT_FALSE(state->hasNotifications());
+        sb_noti_pair = problem_->getStateBlockNotificationMap().erase(sb_noti_pair);
     }
-
-    states.clear();
+    ASSERT_TRUE(problem_->getStateBlockNotificationMap().empty());
   }
 
   ProblemPtr problem_;
@@ -131,45 +114,55 @@ TEST(TrajectoryBase, Add_Remove_Frame)
     FrameBasePtr f2 = std::make_shared<FrameBase>(KEY_FRAME,     2, make_shared<StateBlock>(2), make_shared<StateBlock>(1, true)); // 1 fixed, 1 not
     FrameBasePtr f3 = std::make_shared<FrameBase>(NON_KEY_FRAME, 3, make_shared<StateBlock>(2), make_shared<StateBlock>(1)); // non-key-frame
 
+    std::cout << __LINE__ << std::endl;
+
     // add frames and keyframes
     T->addFrame(f1); // KF
     if (debug) P->print(2,0,0,0);
     ASSERT_EQ(T->getFrameList().                 size(), (unsigned int) 1);
     ASSERT_EQ(P->getStateBlockList().            size(), (unsigned int) 2);
-    ASSERT_EQ(P->getNotifiedStateBlockList().size(),     (unsigned int) 2);
+    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 2);
+    std::cout << __LINE__ << std::endl;
 
     T->addFrame(f2); // KF
     if (debug) P->print(2,0,0,0);
     ASSERT_EQ(T->getFrameList().                 size(), (unsigned int) 2);
     ASSERT_EQ(P->getStateBlockList().            size(), (unsigned int) 4);
-    ASSERT_EQ(P->getNotifiedStateBlockList().size(),     (unsigned int) 4);
+    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 4);
+    std::cout << __LINE__ << std::endl;
 
     T->addFrame(f3); // F
     if (debug) P->print(2,0,0,0);
     ASSERT_EQ(T->getFrameList().                 size(), (unsigned int) 3);
     ASSERT_EQ(P->getStateBlockList().            size(), (unsigned int) 4);
-    ASSERT_EQ(P->getNotifiedStateBlockList().size(),     (unsigned int) 4);
+    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 4);
+    std::cout << __LINE__ << std::endl;
 
     ASSERT_EQ(T->getLastFramePtr()->id(), f3->id());
     ASSERT_EQ(T->getLastKeyFramePtr()->id(), f2->id());
+    std::cout << __LINE__ << std::endl;
 
     N.update();
+    std::cout << __LINE__ << std::endl;
 
     // remove frames and keyframes
     f2->remove(); // KF
     if (debug) P->print(2,0,0,0);
     ASSERT_EQ(T->getFrameList().                 size(), (unsigned int) 2);
     ASSERT_EQ(P->getStateBlockList().            size(), (unsigned int) 2);
-    ASSERT_EQ(P->getNotifiedStateBlockList().size(),     (unsigned int) 2);
+    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 2);
+    std::cout << __LINE__ << std::endl;
 
     ASSERT_EQ(T->getLastFramePtr()->id(), f3->id());
     ASSERT_EQ(T->getLastKeyFramePtr()->id(), f1->id());
+    std::cout << __LINE__ << std::endl;
 
     f3->remove(); // F
     if (debug) P->print(2,0,0,0);
     ASSERT_EQ(T->getFrameList().                 size(), (unsigned int) 1);
     ASSERT_EQ(P->getStateBlockList().            size(), (unsigned int) 2);
-    ASSERT_EQ(P->getNotifiedStateBlockList().size(),     (unsigned int) 2);
+    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 2);
+    std::cout << __LINE__ << std::endl;
 
     ASSERT_EQ(T->getLastKeyFramePtr()->id(), f1->id());
 
@@ -177,11 +170,13 @@ TEST(TrajectoryBase, Add_Remove_Frame)
     if (debug) P->print(2,0,0,0);
     ASSERT_EQ(T->getFrameList().                 size(), (unsigned int) 0);
     ASSERT_EQ(P->getStateBlockList().            size(), (unsigned int) 0);
-    ASSERT_EQ(P->getNotifiedStateBlockList().size(),     (unsigned int) 4);
+    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 4);
+    std::cout << __LINE__ << std::endl;
 
     N.update();
 
-    ASSERT_EQ(P->getNotifiedStateBlockList().size(),     (unsigned int) 0);
+    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 0);
+    std::cout << __LINE__ << std::endl;
 }
 
 TEST(TrajectoryBase, KeyFramesAreSorted)