diff --git a/include/base/ceres_wrapper/ceres_manager.h b/include/base/ceres_wrapper/ceres_manager.h
index c15355fbd0c2cdaae9ea1c39c7032bb311b3b3e9..a20d684d8a5301c325638d90dba4039935ca87de 100644
--- a/include/base/ceres_wrapper/ceres_manager.h
+++ b/include/base/ceres_wrapper/ceres_manager.h
@@ -9,7 +9,7 @@
 //wolf includes
 #include "base/solver/solver_manager.h"
 #include "base/ceres_wrapper/cost_function_wrapper.h"
-#include "local_parametrization_wrapper.h"
+#include "base/ceres_wrapper/local_parametrization_wrapper.h"
 #include "base/ceres_wrapper/create_numeric_diff_cost_function.h"
 
 namespace ceres {
@@ -50,6 +50,11 @@ class CeresManager : public SolverManager
 
         ceres::Solver::Summary getSummary();
 
+        std::unique_ptr<ceres::Problem>& getCeresProblem()
+        {
+            return ceres_problem_;
+        }
+
         virtual void computeCovariances(CovarianceBlocksToBeComputed _blocks
                                         = CovarianceBlocksToBeComputed::ROBOT_LANDMARKS) override;
 
diff --git a/include/base/problem/problem.h b/include/base/problem/problem.h
index bfae71978ca916f52616d8f3af7c88160ca056c4..85838819bfc2febcefde4d6fc0867e445bea8256 100644
--- a/include/base/problem/problem.h
+++ b/include/base/problem/problem.h
@@ -22,6 +22,7 @@ struct ProcessorParamsBase;
 #include "base/state_block/state_block.h"
 
 // std includes
+#include <mutex>
 
 namespace wolf {
 
@@ -41,11 +42,13 @@ class Problem : public std::enable_shared_from_this<Problem>
         TrajectoryBasePtr   trajectory_ptr_;
         MapBasePtr          map_ptr_;
         ProcessorMotionPtr  processor_motion_ptr_;
-        StateBlockPtrList      state_block_list_;
         std::map<std::pair<StateBlockPtr, StateBlockPtr>, Eigen::MatrixXs> covariances_;
         SizeEigen state_size_, state_cov_size_, dim_;
         std::map<FactorBasePtr, Notification> factor_notification_map_;
         std::map<StateBlockPtr, Notification> state_block_notification_map_;
+        mutable std::mutex mut_factor_notifications_;
+        mutable std::mutex mut_state_block_notifications_;
+        mutable std::mutex mut_covariances_;
         bool prior_is_set_;
 
     private: // CAUTION: THESE METHODS ARE PRIVATE, DO NOT MAKE THEM PUBLIC !!
@@ -257,10 +260,6 @@ class Problem : public std::enable_shared_from_this<Problem>
 
         // Solver management ----------------------------------------
 
-        /** \brief Gets a reference to the state blocks list
-         */
-        StateBlockPtrList& getStateBlockPtrList();
-
         /** \brief Notifies a new state block to be added to the solver manager
          */
         StateBlockPtr addStateBlock(StateBlockPtr _state_ptr);
@@ -269,9 +268,9 @@ class Problem : public std::enable_shared_from_this<Problem>
          */
         void removeStateBlock(StateBlockPtr _state_ptr);
 
-        /** \brief Gets a map of factor notification to be handled by the solver
+        /** \brief Returns the map of factor notification to be handled by the solver (the map stored in this is emptied)
          */
-        std::map<StateBlockPtr,Notification>& getStateBlockNotificationMap();
+        std::map<StateBlockPtr,Notification> consumeStateBlockNotificationMap();
 
         /** \brief Notifies a new factor to be added to the solver manager
          */
@@ -281,9 +280,9 @@ class Problem : public std::enable_shared_from_this<Problem>
          */
         void removeFactor(FactorBasePtr _factor_ptr);
 
-        /** \brief Gets a map of factor notification to be handled by the solver
+        /** \brief Returns the map of factor notification to be handled by the solver (the map stored in this is emptied)
          */
-        std::map<FactorBasePtr, Notification>& getFactorNotificationMap();
+        std::map<FactorBasePtr, Notification> consumeFactorNotificationMap();
 
         // Print and check ---------------------------------------
         /**
@@ -322,14 +321,16 @@ inline ProcessorMotionPtr& Problem::getProcessorMotion()
     return processor_motion_ptr_;
 }
 
-inline std::map<StateBlockPtr,Notification>& Problem::getStateBlockNotificationMap()
+inline std::map<StateBlockPtr,Notification> Problem::consumeStateBlockNotificationMap()
 {
-    return state_block_notification_map_;
+    std::lock_guard<std::mutex> lock(mut_state_block_notifications_);
+    return std::move(state_block_notification_map_);
 }
 
-inline std::map<FactorBasePtr,Notification>& Problem::getFactorNotificationMap()
+inline std::map<FactorBasePtr,Notification> Problem::consumeFactorNotificationMap()
 {
-    return factor_notification_map_;
+    std::lock_guard<std::mutex> lock(mut_factor_notifications_);
+    return std::move(factor_notification_map_);
 }
 
 } // namespace wolf
diff --git a/src/ceres_wrapper/ceres_manager.cpp b/src/ceres_wrapper/ceres_manager.cpp
index 2b9b1bc6a52fe7556488000539fa5da2ff88bb84..3d97d7a1df857c7a950b762e4b8082eb99c0056c 100644
--- a/src/ceres_wrapper/ceres_manager.cpp
+++ b/src/ceres_wrapper/ceres_manager.cpp
@@ -267,6 +267,9 @@ void CeresManager::addFactor(const FactorBasePtr& fac_ptr)
 
     auto loss_func_ptr = (fac_ptr->getApplyLossFunction()) ? new ceres::CauchyLoss(0.5) : nullptr;
 
+    //std::cout << "Added residual block corresponding to constraint " << std::static_pointer_cast<CostFunctionWrapper>(cost_func_ptr)->getConstraintPtr()->getType() << std::static_pointer_cast<CostFunctionWrapper>(cost_func_ptr)->getConstraintPtr()->id() <<std::endl;
+
+    assert((unsigned int)(ceres_problem_->NumResidualBlocks()) == fac_2_residual_idx_.size() && "ceres residuals different from wrapper residuals");
     assert(fac_2_residual_idx_.find(fac_ptr) == fac_2_residual_idx_.end() && "adding a factor that is already in the fac_2_residual_idx_ map");
 
     fac_2_residual_idx_[fac_ptr] = ceres_problem_->AddResidualBlock(cost_func_ptr.get(),
@@ -304,11 +307,15 @@ void CeresManager::addStateBlock(const StateBlockPtr& state_ptr)
                                       state_ptr->getSize(),
                                       local_parametrization_ptr);
 
+    if (state_ptr->isFixed())
+        ceres_problem_->SetParameterBlockConstant(getAssociatedMemBlockPtr(state_ptr));
+
     updateStateBlockStatus(state_ptr);
 }
 
 void CeresManager::removeStateBlock(const StateBlockPtr& state_ptr)
 {
+    //std::cout << "CeresManager::removeStateBlock " << state_ptr.get() << " - " << getAssociatedMemBlockPtr(state_ptr) << std::endl;
     assert(state_ptr);
     ceres_problem_->RemoveParameterBlock(getAssociatedMemBlockPtr(state_ptr));
     state_blocks_local_param_.erase(state_ptr);
diff --git a/src/problem/problem.cpp b/src/problem/problem.cpp
index 0d9f055b259a1558822ded587872299feeb93a1a..8e607b0d4e7891e7978d4b2b127a8eabbe367cac 100644
--- a/src/problem/problem.cpp
+++ b/src/problem/problem.cpp
@@ -425,15 +425,8 @@ void Problem::addLandmarkList(LandmarkBasePtrList& _lmk_list)
 
 StateBlockPtr Problem::addStateBlock(StateBlockPtr _state_ptr)
 {
+    std::lock_guard<std::mutex> lock(mut_state_block_notifications_);
     //std::cout << "Problem::addStateBlockPtr " << _state_ptr.get() << std::endl;
-    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
     // Check if there is already a notification for this state block
@@ -450,16 +443,8 @@ StateBlockPtr Problem::addStateBlock(StateBlockPtr _state_ptr)
 
 void Problem::removeStateBlock(StateBlockPtr _state_ptr)
 {
+    std::lock_guard<std::mutex> lock(mut_state_block_notifications_);
     //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);
 
     // Check if there is already a notification for this state block
     auto notification_it = state_block_notification_map_.find(_state_ptr);
@@ -482,6 +467,7 @@ void Problem::removeStateBlock(StateBlockPtr _state_ptr)
 
 FactorBasePtr Problem::addFactor(FactorBasePtr _factor_ptr)
 {
+    std::lock_guard<std::mutex> lock(mut_factor_notifications_);
     //std::cout << "Problem::addFactorPtr " << _factor_ptr->id() << std::endl;
 
     // Add ADD notification
@@ -500,6 +486,7 @@ FactorBasePtr Problem::addFactor(FactorBasePtr _factor_ptr)
 
 void Problem::removeFactor(FactorBasePtr _factor_ptr)
 {
+    std::lock_guard<std::mutex> lock(mut_factor_notifications_);
     //std::cout << "Problem::removeFactorPtr " << _factor_ptr->id() << std::endl;
 
     // Check if there is already a notification for this state block
@@ -521,6 +508,7 @@ void Problem::removeFactor(FactorBasePtr _factor_ptr)
 
 void Problem::clearCovariance()
 {
+    std::lock_guard<std::mutex> lock(mut_covariances_);
     covariances_.clear();
 }
 
@@ -529,6 +517,7 @@ void Problem::addCovarianceBlock(StateBlockPtr _state1, StateBlockPtr _state2, c
     assert(_state1->getSize() == (unsigned int ) _cov.rows() && "wrong covariance block size");
     assert(_state2->getSize() == (unsigned int ) _cov.cols() && "wrong covariance block size");
 
+    std::lock_guard<std::mutex> lock(mut_covariances_);
     covariances_[std::pair<StateBlockPtr, StateBlockPtr>(_state1, _state2)] = _cov;
 }
 
@@ -537,6 +526,7 @@ void Problem::addCovarianceBlock(StateBlockPtr _state1, const Eigen::MatrixXs& _
     assert(_state1->getSize() == (unsigned int ) _cov.rows() && "wrong covariance block size");
     assert(_state1->getSize() == (unsigned int ) _cov.cols() && "wrong covariance block size");
 
+    std::lock_guard<std::mutex> lock(mut_covariances_);
     covariances_[std::make_pair(_state1, _state1)] = _cov;
 }
 
@@ -556,6 +546,8 @@ bool Problem::getCovarianceBlock(StateBlockPtr _state1, StateBlockPtr _state2, E
 
     assert(_row + _state1->getSize() <= _cov.rows() && _col + _state2->getSize() <= _cov.cols() && "Problem::getCovarianceBlock: Bad matrix covariance size!");
 
+    std::lock_guard<std::mutex> lock(mut_covariances_);
+
     if (covariances_.find(std::pair<StateBlockPtr, StateBlockPtr>(_state1, _state2)) != covariances_.end())
         _cov.block(_row, _col, _state1->getSize(), _state2->getSize()) =
                 covariances_[std::pair<StateBlockPtr, StateBlockPtr>(_state1, _state2)];
@@ -573,6 +565,8 @@ bool Problem::getCovarianceBlock(StateBlockPtr _state1, StateBlockPtr _state2, E
 
 bool Problem::getCovarianceBlock(std::map<StateBlockPtr, unsigned int> _sb_2_idx, Eigen::MatrixXs& _cov)
 {
+    std::lock_guard<std::mutex> lock(mut_covariances_);
+
     // fill covariance
     for (auto it1 = _sb_2_idx.begin(); it1 != _sb_2_idx.end(); it1++)
         for (auto it2 = it1; it2 != _sb_2_idx.end(); it2++)
@@ -719,11 +713,6 @@ FrameBasePtr Problem::getLastKeyFrame()
     return trajectory_ptr_->getLastKeyFrame();
 }
 
-StateBlockPtrList& Problem::getStateBlockPtrList()
-{
-    return state_block_list_;
-}
-
 FrameBasePtr Problem::setPrior(const Eigen::VectorXs& _prior_state, const Eigen::MatrixXs& _prior_cov, const TimeStamp& _ts, const Scalar _time_tolerance)
 {
     if ( ! prior_is_set_ )
diff --git a/src/solver/solver_manager.cpp b/src/solver/solver_manager.cpp
index adc0dabd9d9ae889b95ba2b2aaf33b7237094d3a..2a914ef672f7b31463d8f5309e147c52016101b6 100644
--- a/src/solver/solver_manager.cpp
+++ b/src/solver/solver_manager.cpp
@@ -13,26 +13,30 @@ SolverManager::SolverManager(const ProblemPtr& _wolf_problem) :
 
 void SolverManager::update()
 {
+    // Consume notification maps
+    auto fac_notification_map = wolf_problem_->consumeFactorNotificationMap();
+    auto sb_notification_map = wolf_problem_->consumeStateBlockNotificationMap();
+
     // REMOVE CONSTRAINTS
-    auto fac_notification_it = wolf_problem_->getFactorNotificationMap().begin();
-    while ( fac_notification_it != wolf_problem_->getFactorNotificationMap().end() )
+    for (auto fac_notification_it = fac_notification_map.begin();
+         fac_notification_it != fac_notification_map.end();
+         /* nothing, next is handled within the for */)
     {
         if (fac_notification_it->second == REMOVE)
         {
             removeFactor(fac_notification_it->first);
-            fac_notification_it = wolf_problem_->getFactorNotificationMap().erase(fac_notification_it);
+            fac_notification_it = fac_notification_map.erase(fac_notification_it);
         }
         else
             fac_notification_it++;
     }
 
     // ADD/REMOVE STATE BLOCS
-    auto sb_notification_it = wolf_problem_->getStateBlockNotificationMap().begin();
-    while ( sb_notification_it != wolf_problem_->getStateBlockNotificationMap().end() )
+    while ( !sb_notification_map.empty() )
     {
-        StateBlockPtr state_ptr = sb_notification_it->first;
+        StateBlockPtr state_ptr = sb_notification_map.begin()->first;
 
-        if (sb_notification_it->second == ADD)
+        if (sb_notification_map.begin()->second == ADD)
         {
             // only add if not added
             if (state_blocks_.find(state_ptr) == state_blocks_.end())
@@ -46,7 +50,7 @@ void SolverManager::update()
             }
             else
             {
-                WOLF_DEBUG("Tried adding an already registered StateBlock.");
+                WOLF_DEBUG("Tried to add an already added !");
             }
         }
         else
@@ -63,26 +67,24 @@ void SolverManager::update()
             }
         }
         // next notification
-        sb_notification_it = wolf_problem_->getStateBlockNotificationMap().erase(sb_notification_it);
+        sb_notification_map.erase(sb_notification_map.begin());
     }
 
     // ADD CONSTRAINTS
-    fac_notification_it = wolf_problem_->getFactorNotificationMap().begin();
-    while (fac_notification_it != wolf_problem_->getFactorNotificationMap().end())
+    while (!fac_notification_map.empty())
     {
-        assert(wolf_problem_->getFactorNotificationMap().begin()->second == ADD && "unexpected factor notification value after all REMOVE have been processed, this should be ADD");
+        assert(fac_notification_map.begin()->second == ADD && "unexpected factor notification value after all REMOVE have been processed, this should be ADD");
 
-        addFactor(wolf_problem_->getFactorNotificationMap().begin()->first);
-        fac_notification_it = wolf_problem_->getFactorNotificationMap().erase(fac_notification_it);
+        // add factor
+        addFactor(fac_notification_map.begin()->first);
+        // remove notification
+        fac_notification_map.erase(fac_notification_map.begin());
     }
 
     // UPDATE STATE BLOCKS (state, fix or local parameterization)
-    for (auto state_ptr : wolf_problem_->getStateBlockPtrList())
+    for (auto state_pair : state_blocks_)
     {
-        if (state_blocks_.find(state_ptr)==state_blocks_.end())
-            continue;
-
-        assert(state_blocks_.find(state_ptr)!=state_blocks_.end() && "Updating the state of an unregistered StateBlock !");
+        auto state_ptr = state_pair.first;
 
         // state update
         if (state_ptr->stateUpdated())
@@ -108,9 +110,6 @@ void SolverManager::update()
             state_ptr->resetLocalParamUpdated();
         }
     }
-
-    //assert(wolf_problem_->getFactorNotificationMap().empty() && "wolf problem's factors 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::getProblem()
diff --git a/test/gtest_ceres_manager.cpp b/test/gtest_ceres_manager.cpp
index 78492ae19bdc78f500f50830ea093bcc4f16c35f..9b096f7c82d24aa1b2b939919f46a5190f8a65c0 100644
--- a/test/gtest_ceres_manager.cpp
+++ b/test/gtest_ceres_manager.cpp
@@ -398,12 +398,10 @@ TEST(CeresManager, AddRemoveFactor)
     FeatureBasePtr      f = C->addFeature(std::make_shared<FeatureBase>("ODOM 2D", Vector3s::Zero(), Matrix3s::Identity()));
     FactorPose2DPtr c = std::static_pointer_cast<FactorPose2D>(f->addFactor(std::make_shared<FactorPose2D>(f)));
 
-    ASSERT_TRUE(P->getFactorNotificationMap().begin()->first == c);
-
     // remove factor
     P->removeFactor(c);
 
-    ASSERT_TRUE(P->getFactorNotificationMap().empty());
+    ASSERT_TRUE(P->consumeFactorNotificationMap().empty()); // add+remove = empty
 
     // update solver
     ceres_manager_ptr->update();
diff --git a/test/gtest_problem.cpp b/test/gtest_problem.cpp
index 2c5102882ac6ee6c9bd25aeb46c847df56b7162a..213e29b9e8acb4c4af36da0c6365d1a538aa2d69 100644
--- a/test/gtest_problem.cpp
+++ b/test/gtest_problem.cpp
@@ -207,13 +207,11 @@ 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->getStateBlockPtrList().size(), (unsigned int) 2);
-    ASSERT_EQ(P->getStateBlockNotificationMap().size(), (unsigned int) 2);
+    ASSERT_EQ(P->consumeStateBlockNotificationMap().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->getStateBlockPtrList().size(), (unsigned int) (2 + 3));
-    ASSERT_EQ(P->getStateBlockNotificationMap().size(), (unsigned int) (2 + 3));
+    ASSERT_EQ(P->consumeStateBlockNotificationMap().size(), (unsigned int) (/*2 + */3)); // consume empties the notification map, so only should contain notification since last call
 
     ProcessorParamsTrackerFeaturePtr params = std::make_shared<ProcessorParamsTrackerFeature>();
     params->time_tolerance            = 0.1;
@@ -226,15 +224,13 @@ TEST(Problem, StateBlocks)
 
     // 2 state blocks, estimated
     P->emplaceFrame("PO 3D", KEY_FRAME, xs, 0);
-    ASSERT_EQ(P->getStateBlockPtrList().size(), (unsigned int)(2 + 3 + 2));
-    ASSERT_EQ(P->getStateBlockNotificationMap().size(), (unsigned int)(2 + 3 + 2));
+    ASSERT_EQ(P->consumeStateBlockNotificationMap().size(), (unsigned int)(/*2 + 3*/ + 2)); // consume empties the notification map, so only should contain notification since last call
 
     //    P->print(4,1,1,1);
 
     // change some SB properties
     St->unfixExtrinsics();
-    ASSERT_EQ(P->getStateBlockPtrList().size(), (unsigned int)(2 + 3 + 2));
-    ASSERT_EQ(P->getStateBlockNotificationMap().size(),(unsigned int)(2 + 3 + 2 /*+ 2*/)); // XXX: 2 more notifications on the same SB!
+    ASSERT_TRUE(P->consumeStateBlockNotificationMap().empty()); // changes in state_blocks status (fix/state/localparam) does not raise a notification in problem, only ADD/REMOVE
 
     //    P->print(4,1,1,1);
 }
diff --git a/test/gtest_solver_manager.cpp b/test/gtest_solver_manager.cpp
index be68ea5ec11cbad46c3154c874ce9bec29d97c33..9de5032b38af32cd564429fae2d0833c60817ef6 100644
--- a/test/gtest_solver_manager.cpp
+++ b/test/gtest_solver_manager.cpp
@@ -445,13 +445,14 @@ TEST(SolverManager, AddUpdatedStateBlock)
     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) ==
+    // == When an ADD is notified: a ADD notification should be stored ==
 
     // add state_block
     P->addStateBlock(sb_ptr);
 
-    ASSERT_EQ(P->getStateBlockNotificationMap().size(),1);
-    ASSERT_EQ(P->getStateBlockNotificationMap().begin()->second,ADD);
+    auto state_block_notification_map = P->consumeStateBlockNotificationMap();
+    ASSERT_EQ(state_block_notification_map.size(),1);
+    ASSERT_EQ(state_block_notification_map.begin()->second,ADD);
 
     // == Insert OTHER notifications ==
 
@@ -462,37 +463,30 @@ TEST(SolverManager, AddUpdatedStateBlock)
     // Fix --> FLAG
     sb_ptr->unfix();
 
-    ASSERT_EQ(P->getStateBlockNotificationMap().size(),1); // only ADD notification (fix and state are flags in sb)
+    ASSERT_TRUE(P->consumeStateBlockNotificationMap().empty()); // No new notifications (fix and set state are flags in sb)
 
-    // == REMOVE should clear the previous notification (ADD) in the stack ==
+    // == When an REMOVE is notified: a REMOVE notification should be stored ==
 
     // remove state_block
     P->removeStateBlock(sb_ptr);
 
-    ASSERT_EQ(P->getStateBlockNotificationMap().size(),0);// ADD + REMOVE = EMPTY
+    state_block_notification_map = P->consumeStateBlockNotificationMap();
+    ASSERT_EQ(state_block_notification_map.size(),1);
+    ASSERT_EQ(state_block_notification_map.begin()->second,REMOVE);
 
-    // == UPDATES + REMOVE should clear the list of notifications ==
+    // == ADD + REMOVE: notification map should be empty ==
+    P->addStateBlock(sb_ptr);
+    P->removeStateBlock(sb_ptr);
+    ASSERT_TRUE(P->consumeStateBlockNotificationMap().empty());
 
+    // == UPDATES 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();
-
-    // Set State
-    state_2 = 2*state;
-    sb_ptr->setState(state_2);
-
-    // remove state_block
-    P->removeStateBlock(sb_ptr);
-
-    ASSERT_EQ(P->getStateBlockNotificationMap().size(),1);
-    ASSERT_EQ(P->getStateBlockNotificationMap().begin()->second, REMOVE);
+    ASSERT_TRUE(P->consumeStateBlockNotificationMap().empty()); // After solver_manager->update, notifications should be empty
 }
 
 TEST(SolverManager, AddFactor)
@@ -560,12 +554,10 @@ TEST(SolverManager, AddRemoveFactor)
     FeatureBasePtr      f = C->addFeature(std::make_shared<FeatureBase>("ODOM 2D", Vector3s::Zero(), Matrix3s::Identity()));
     FactorPose2DPtr c = std::static_pointer_cast<FactorPose2D>(f->addFactor(std::make_shared<FactorPose2D>(f)));
 
-    ASSERT_TRUE(P->getFactorNotificationMap().begin()->first == c);
-
     // add factor
     P->removeFactor(c);
 
-    ASSERT_TRUE(P->getFactorNotificationMap().empty());
+    ASSERT_TRUE(P->consumeFactorNotificationMap().empty()); // ADD+REMOVE = empty
 
     // update solver
     solver_manager_ptr->update();
diff --git a/test/gtest_trajectory.cpp b/test/gtest_trajectory.cpp
index e74519b58be66ea7efb68f805e3e3e15e022e0d7..de582e26b0e3fbfa6ca61876e82d3b9870ea0ff8 100644
--- a/test/gtest_trajectory.cpp
+++ b/test/gtest_trajectory.cpp
@@ -31,10 +31,12 @@ struct DummyNotificationProcessor
       FAIL() << "problem_ is nullptr !";
     }
 
-    auto sb_noti_pair = problem_->getStateBlockNotificationMap().begin();
-    while (sb_noti_pair != problem_->getStateBlockNotificationMap().end())
+    auto sb_noti_map = problem_->consumeStateBlockNotificationMap();
+    ASSERT_TRUE(problem_->consumeStateBlockNotificationMap().empty()); // consume should empty the notification map
+
+    while (!sb_noti_map.empty())
     {
-        switch (sb_noti_pair->second)
+        switch (sb_noti_map.begin()->second)
         {
           case ADD:
           {
@@ -47,9 +49,9 @@ struct DummyNotificationProcessor
           default:
             throw std::runtime_error("SolverManager::update: State Block notification must be ADD or REMOVE.");
         }
-        sb_noti_pair = problem_->getStateBlockNotificationMap().erase(sb_noti_pair);
+        sb_noti_map.erase(sb_noti_map.begin());
     }
-    ASSERT_TRUE(problem_->getStateBlockNotificationMap().empty());
+    ASSERT_TRUE(sb_noti_map.empty());
   }
 
   ProblemPtr problem_;
@@ -118,22 +120,18 @@ TEST(TrajectoryBase, Add_Remove_Frame)
     T->addFrame(f1); // KF
     if (debug) P->print(2,0,0,0);
     ASSERT_EQ(T->getFrameList().                 size(), (unsigned int) 1);
-    ASSERT_EQ(P->getStateBlockPtrList().            size(), (unsigned int) 2);
-    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 2);
+    ASSERT_EQ(P->consumeStateBlockNotificationMap(). 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->getStateBlockPtrList().            size(), (unsigned int) 4);
-    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 4);
     std::cout << __LINE__ << std::endl;
 
-    T->addFrame(f3); // F
+    T->addFrame(f3); // F (not KF so state blocks are not notified)
     if (debug) P->print(2,0,0,0);
     ASSERT_EQ(T->getFrameList().                 size(), (unsigned int) 3);
-    ASSERT_EQ(P->getStateBlockPtrList().            size(), (unsigned int) 4);
-    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 4);
+    ASSERT_EQ(P->consumeStateBlockNotificationMap(). size(), (unsigned int) 2); // consumeStateBlockNotificationMap empties the notification map, 2 state blocks were notified since last call to consumeStateBlockNotificationMap
     std::cout << __LINE__ << std::endl;
 
     ASSERT_EQ(T->getLastFrame()->id(), f3->id());
@@ -141,14 +139,14 @@ TEST(TrajectoryBase, Add_Remove_Frame)
     std::cout << __LINE__ << std::endl;
 
     N.update();
+    ASSERT_TRUE(P->consumeStateBlockNotificationMap().empty()); // consumeStateBlockNotificationMap was called in update() so it should be empty
     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->getStateBlockPtrList().            size(), (unsigned int) 2);
-    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 2);
+    ASSERT_EQ(P->consumeStateBlockNotificationMap(). size(), (unsigned int) 2); // consumeStateBlockNotificationMap empties the notification map, 2 state blocks were notified since last call to consumeStateBlockNotificationMap
     std::cout << __LINE__ << std::endl;
 
     ASSERT_EQ(T->getLastFrame()->id(), f3->id());
@@ -158,8 +156,6 @@ TEST(TrajectoryBase, Add_Remove_Frame)
     f3->remove(); // F
     if (debug) P->print(2,0,0,0);
     ASSERT_EQ(T->getFrameList().                 size(), (unsigned int) 1);
-    ASSERT_EQ(P->getStateBlockPtrList().            size(), (unsigned int) 2);
-    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 2);
     std::cout << __LINE__ << std::endl;
 
     ASSERT_EQ(T->getLastKeyFrame()->id(), f1->id());
@@ -167,13 +163,11 @@ TEST(TrajectoryBase, Add_Remove_Frame)
     f1->remove(); // KF
     if (debug) P->print(2,0,0,0);
     ASSERT_EQ(T->getFrameList().                 size(), (unsigned int) 0);
-    ASSERT_EQ(P->getStateBlockPtrList().            size(), (unsigned int) 0);
-    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 4);
     std::cout << __LINE__ << std::endl;
 
     N.update();
 
-    ASSERT_EQ(P->getStateBlockNotificationMap(). size(), (unsigned int) 0);
+    ASSERT_TRUE(P->consumeStateBlockNotificationMap().empty()); // consumeStateBlockNotificationMap was called in update() so it should be empty
     std::cout << __LINE__ << std::endl;
 }