diff --git a/CMakeLists.txt b/CMakeLists.txt index 98de6dbd9bfb7521238c7c784b077456b35b5629..2cb1b2028d2b29a4d02aea6ca0e94943719b28a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -216,6 +216,7 @@ SET(HDRS_STATE_BLOCK include/core/state_block/local_parametrization_quaternion.h include/core/state_block/state_angle.h include/core/state_block/state_block.h + include/core/state_block/state_composite.h include/core/state_block/state_homogeneous_3d.h include/core/state_block/state_quaternion.h ) @@ -316,6 +317,7 @@ SET(SRCS_STATE_BLOCK src/state_block/local_parametrization_homogeneous.cpp src/state_block/local_parametrization_quaternion.cpp src/state_block/state_block.cpp + src/state_block/state_composite.cpp ) SET(SRCS_COMMON src/common/node_base.cpp diff --git a/include/core/common/wolf.h b/include/core/common/wolf.h index 3c0593f670d2a8cbf5ce4418734b8fd571766407..8f801a6a8620a0f5e05af911ce4daf9f26783eee 100644 --- a/include/core/common/wolf.h +++ b/include/core/common/wolf.h @@ -106,10 +106,6 @@ typedef Matrix<double,Dynamic,Dynamic,RowMajor> MatrixRowXd; ///< dynamic rowmaj namespace wolf { -/// State of nodes containing several state blocks -typedef std::unordered_map<std::string, Eigen::VectorXd> StateComposite; -typedef std::string StateStructure; - ////////////////////////////////////////////////////////// /** Check Eigen Matrix sizes, both statically and dynamically diff --git a/include/core/processor/is_motion.h b/include/core/processor/is_motion.h index e289ec29854b510f2b99a763bca2d3f3758e11f2..84cf09e093e4dde53a704383cf39135e7b89c8e0 100644 --- a/include/core/processor/is_motion.h +++ b/include/core/processor/is_motion.h @@ -9,7 +9,7 @@ #define PROCESSOR_IS_MOTION_H_ #include "core/common/wolf.h" -//#include "core/state_block/has_state_blocks.h" +#include "core/state_block/state_composite.h" namespace wolf { diff --git a/include/core/state_block/has_state_blocks.h b/include/core/state_block/has_state_blocks.h index 958b4f199e4a69eb41e8edd78d78fe2bf7834c5f..58c79858b9134fe38fe34dc91e3a93708a0b6db1 100644 --- a/include/core/state_block/has_state_blocks.h +++ b/include/core/state_block/has_state_blocks.h @@ -9,6 +9,7 @@ #define STATE_BLOCK_HAS_STATE_BLOCKS_H_ #include "core/common/wolf.h" +#include "core/state_block/state_composite.h" #include <unordered_map> @@ -262,30 +263,6 @@ inline Eigen::VectorXd HasStateBlocks::getState(const StateStructure& _sub_struc return state; } -inline bool HasStateBlocks::getStateComposite(StateComposite& _state) const -{ - for (auto& pair_key_sb : state_block_map_) - { - _state.emplace(pair_key_sb.first, pair_key_sb.second->getState()); - } - return true; -} - -inline StateComposite HasStateBlocks::getStateComposite() const -{ - StateComposite state; - getStateComposite(state); - return state; -} - -inline void HasStateBlocks::setStateComposite(const StateComposite &_state) -{ - for (const auto& pair_key_sb : _state) - { - state_block_map_[pair_key_sb.first]->setState(pair_key_sb.second); - } -} - inline std::unordered_map<std::string, StateBlockPtr>::const_iterator HasStateBlocks::find(const StateBlockPtr& _sb) const { const auto& it = std::find_if(state_block_map_.begin(), diff --git a/include/core/state_block/state_composite.h b/include/core/state_block/state_composite.h new file mode 100644 index 0000000000000000000000000000000000000000..76b476aa33daebd713c447de5be17102c4f6e608 --- /dev/null +++ b/include/core/state_block/state_composite.h @@ -0,0 +1,93 @@ +/* + * state_composite.h + * + * Created on: Apr 6, 2020 + * Author: jsola + */ + +#ifndef STATE_BLOCK_STATE_COMPOSITE_H_ +#define STATE_BLOCK_STATE_COMPOSITE_H_ + +#include "core/common/wolf.h" + +#include <unordered_map> + +#include <iostream> + + +namespace wolf +{ + +using std::string; +using namespace Eigen; + +/// State of nodes containing several state blocks, and Jacobians +typedef std::string StateStructure; +typedef std::unordered_map < std::string, Eigen::VectorXd > StateComposite; + + +class MatrixComposite +{ + + private: + std::unordered_map < std::string, std::unordered_map < std::string, Eigen::MatrixXd > > matrix_composite_; + std::unordered_map < string, unsigned int> size_rows_, size_cols_; + + public: + MatrixComposite() = default; + virtual ~MatrixComposite() = default; + + unsigned int count(const std::string &_row, + const std::string &_col) const; + + bool emplace(const std::string &_row, + const std::string &_col, + const Eigen::MatrixXd &_mat_blk); + + bool at(const std::string &_row, + const std::string &_col, + Eigen::MatrixXd &_mat_blk) const; + const MatrixXd& at(const std::string &_row, + const std::string &_col) const; + MatrixXd& at(const std::string &_row, + const std::string &_col); + + MatrixXd& operator ()(const std::string &_row, + const std::string &_col); + const MatrixXd& operator ()(const std::string &_row, + const std::string &_col) const; + + StateComposite operator *(const StateComposite &_second) const; + MatrixComposite operator *(const MatrixComposite &_second) const; + + friend std::ostream& operator << (std::ostream& _os, const MatrixComposite& _M); +}; + + + + +inline const Eigen::MatrixXd& MatrixComposite::operator ()(const std::string &_row, const std::string &_col) const +{ + return matrix_composite_.at(_row).at(_col); +} + +inline Eigen::MatrixXd& MatrixComposite::operator ()(const std::string &_row, const std::string &_col) +{ + return matrix_composite_[_row][_col]; +} + +inline unsigned int MatrixComposite::count(const std::string &_row, const std::string &_col) const +{ + if (matrix_composite_.count(_row) == 0) + return 0; + + return (matrix_composite_.at(_row).count(_col)); +} + +std::ostream& operator <<(std::ostream &_os, const StateComposite &_x); + +} + + + +#endif /* STATE_BLOCK_STATE_COMPOSITE_H_ */ diff --git a/src/state_block/has_state_blocks.cpp b/src/state_block/has_state_blocks.cpp index 83cf44b26bdfcad7e415633ef6d8fe783564a75c..55a343f735d5b55a796e1dec3537927331fead4c 100644 --- a/src/state_block/has_state_blocks.cpp +++ b/src/state_block/has_state_blocks.cpp @@ -44,6 +44,30 @@ void HasStateBlocks::removeStateBlocks(ProblemPtr _problem) } } +bool HasStateBlocks::getStateComposite(StateComposite &_state) const +{ + for (auto &pair_key_sb : state_block_map_) + { + _state.emplace(pair_key_sb.first, pair_key_sb.second->getState()); + } + return true; +} + +StateComposite HasStateBlocks::getStateComposite() const +{ + StateComposite state; + getStateComposite(state); + return state; +} + +void HasStateBlocks::setStateComposite(const StateComposite &_state) +{ + for (const auto &pair_key_sb : _state) + { + state_block_map_[pair_key_sb.first]->setState(pair_key_sb.second); + } +} + void HasStateBlocks::perturb(double amplitude) { for (const auto& pair_key_sb : state_block_map_) diff --git a/src/state_block/state_composite.cpp b/src/state_block/state_composite.cpp new file mode 100644 index 0000000000000000000000000000000000000000..84a7a526a3f05b8d1728f07cc4fc08fc672589ad --- /dev/null +++ b/src/state_block/state_composite.cpp @@ -0,0 +1,136 @@ + + + +#include "core/state_block/state_composite.h" + +namespace wolf +{ + +bool MatrixComposite::emplace(const std::string &_row, const std::string &_col, const Eigen::MatrixXd &_mat_blk) +{ + // check rows + if (size_rows_.count(_row) == 0) + size_rows_[_row] = _mat_blk.rows(); + else + assert(size_rows_.at(_row) == _mat_blk.rows() && "Provided matrix block has wrong number of rows!"); + + // check cols + if (size_cols_.count(_col) == 0) + size_cols_[_col] = _mat_blk.cols(); + else + assert(size_rows_.at(_row) == _mat_blk.rows() && "Provided matrix block has wrong number of rows!"); + + // now it's safe to use [] operator + matrix_composite_[_row][_col] = _mat_blk; + return true; +} + +bool MatrixComposite::at(const std::string &_row, const std::string &_col, Eigen::MatrixXd &_mat_blk) const +{ + const auto &row_it = matrix_composite_.find(_row); + if(row_it != matrix_composite_.end()) + return false; + + const auto &col_it = row_it->second.find(_col); + if(col_it != row_it->second.end()) + return false; + + _mat_blk = col_it->second; + + return true; +} + +Eigen::MatrixXd& MatrixComposite::at(const std::string &_row, const std::string &_col) +{ + const auto &row_it = matrix_composite_.find(_row); + assert(row_it != matrix_composite_.end() && "Requested matrix block does not exist in matrix composite."); + + const auto &col_it = row_it->second.find(_col); + assert(col_it != row_it->second.end() && "Requested matrix block does not exist in matrix composite."); + + return col_it->second; +} + +const Eigen::MatrixXd& MatrixComposite::at(const std::string &_row, const std::string &_col) const +{ + const auto &row_it = matrix_composite_.find(_row); + assert(row_it != matrix_composite_.end() && "Requested matrix block does not exist in matrix composite."); + + const auto &col_it = row_it->second.find(_col); + assert(col_it != row_it->second.end() && "Requested matrix block does not exist in matrix composite."); + + return col_it->second; +} + +wolf::MatrixComposite MatrixComposite::operator *(const MatrixComposite &_N) const +{ + MatrixComposite MN; + for (const auto &pair_i_Mi : this->matrix_composite_) + { + const auto &i = pair_i_Mi.first; + const auto &Mi = pair_i_Mi.second; + for (const auto &pair_k_Nk : _N.matrix_composite_) + { + const auto &k = pair_k_Nk.first; + const auto &Nk = pair_k_Nk.second; + for (const auto &pair_j_Nkj : Nk) + { + const auto &j = pair_j_Nkj.first; + const auto &Nkj = pair_j_Nkj.second; + const auto &Mik = Mi.at(k); + if (MN.count(i, j) == 0) + MN.emplace(i, j, Mik * Nkj); + else + MN.at(i, j) += Mik * Nkj; + } + } + } + return MN; +} + +wolf::StateComposite MatrixComposite::operator *(const StateComposite &_x) const +{ + StateComposite y; + for (const auto &pair_rkey_row : matrix_composite_) + { + const auto &rkey = pair_rkey_row.first; + const auto &row = pair_rkey_row.second; + for (const auto &pair_ckey_mat : row) + { + const auto &ckey = pair_ckey_mat.first; + const auto &J_r_c = pair_ckey_mat.second; + if (y.count(rkey)) + y.at(rkey) += J_r_c * _x.at(ckey); + else + y.emplace(rkey, J_r_c * _x.at(ckey)); + } + } + return y; +} + +std::ostream& operator <<(std::ostream &_os, const MatrixComposite &_M) +{ + for (const auto &pair_row_cols : _M.matrix_composite_) + { + const auto row = pair_row_cols.first; + for (const auto &pair_col_blk : pair_row_cols.second) + { + const auto &col = pair_col_blk.first; + _os << "\n block(" << row << "," << col << ") = \n" << pair_col_blk.second; + } + } + return _os; +} + +std::ostream& operator <<(std::ostream &_os, const StateComposite &_x) +{ + for (const auto &pair_row_blk : _x) + { + const auto &row = pair_row_blk.first; + const auto &vec = pair_row_blk.second; + _os << "\n block(" << row << ") = \n" << vec; + } + return _os; +} + +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 501965cdff67102f807e482f87ca7eafb7109e54..2558c2452ea038d9b622c06a863c754424ed988a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -31,11 +31,13 @@ wolf_add_gtest(gtest_example gtest_example.cpp) # target_link_libraries(gtest_example ${PROJECT_NAME}) # # # ########################################################### + set(SRC_DUMMY dummy/processor_tracker_feature_dummy.cpp dummy/processor_tracker_landmark_dummy.cpp ) add_library(dummy ${SRC_DUMMY}) + ################# ADD YOUR TESTS BELOW #################### # # # ==== IN ALPHABETICAL ORDER! ==== # @@ -137,6 +139,10 @@ target_link_libraries(gtest_solver_manager ${PROJECT_NAME}) wolf_add_gtest(gtest_state_block gtest_state_block.cpp) target_link_libraries(gtest_state_block ${PROJECT_NAME}) +# StateComposite class test +wolf_add_gtest(gtest_state_composite gtest_state_composite.cpp) +target_link_libraries(gtest_state_composite ${PROJECT_NAME}) + # TimeStamp class test wolf_add_gtest(gtest_time_stamp gtest_time_stamp.cpp) target_link_libraries(gtest_time_stamp ${PROJECT_NAME}) diff --git a/test/gtest_state_composite.cpp b/test/gtest_state_composite.cpp new file mode 100644 index 0000000000000000000000000000000000000000..abda2f373f2e0d951b8206518711a5efe6e3505e --- /dev/null +++ b/test/gtest_state_composite.cpp @@ -0,0 +1,182 @@ +/* + * gtest_state_composite.cpp + * + * Created on: Apr 6, 2020 + * Author: jsola + */ + + +#include "core/utils/utils_gtest.h" +#include "core/utils/logging.h" + +#include "core/state_block/state_composite.h" + +using namespace wolf; + +/* +// You may use this to make some methods of Foo public +WOLF_PTR_TYPEDEFS(FooPublic); +class FooPublic : public Foo +{ + // You may use this to make some methods of Foo public +} + +class TestInit : public testing::Test +{ + // You may use this to initialize stuff + // Combine it with TEST_F(FooTest, testName) { } + SetUp() + { + // Init all you want here + // e.g. FooPublic foo; + } + TearDown(){} +}; + +TEST_F(TestInit, testName) +{ + // Use class TestInit +} +*/ + +using namespace std; + +TEST(StateComposite, operatorStream) +{ + StateComposite x; + unsigned int psize, osize; + psize = 2; + osize = 3; + + x.emplace("P", Vector2d(1,1)); + x.emplace("O", Vector3d(2,2,2)); + + WOLF_DEBUG("x = " , x); + +} +TEST(MatrixComposite, emplace_operatorStream) +{ + MatrixComposite M; + + unsigned int psize, osize; + psize = 2; + osize = 3; + + MatrixXd Mpp(psize,psize), Mpo(psize, osize), Mop(osize,psize), Moo(osize,osize); + + Mpp.setOnes(); + Mpo.setOnes(); Mpo *= 2; + Mop.setOnes(); Mop *= 3; + Moo.setOnes(); Moo *= 4; + + + ASSERT_TRUE(M.emplace("P", "P", Mpp)); + WOLF_DEBUG("M = " , M); + + ASSERT_TRUE(M.emplace("P", "O", Mpo)); + WOLF_DEBUG("M = " , M); + + ASSERT_TRUE(M.emplace("O", "P", Mop)); + WOLF_DEBUG("M = " , M); + + ASSERT_TRUE(M.emplace("O", "O", Moo)); + WOLF_DEBUG("M = " , M); +} + +TEST(MatrixComposite, productVector) +{ + unsigned int psize, osize; + psize = 2; + osize = 3; + + StateComposite x; + x.emplace("P", Vector2d(1,1)); + x.emplace("O", Vector3d(2,2,2)); + + WOLF_DEBUG("x = " , x); + + MatrixComposite M; + + MatrixXd Mpp(psize,psize), Mpo(psize, osize), Mop(osize,psize), Moo(osize,osize); + Mpp.setOnes(); + Mpo.setOnes(); Mpo *= 2; + Mop.setOnes(); Mop *= 3; + Moo.setOnes(); Moo *= 4; + + M.emplace("P", "P", Mpp); + M.emplace("P", "O", Mpo); + M.emplace("O", "P", Mop); + M.emplace("O", "O", Moo); + WOLF_DEBUG("M = " , M); + + StateComposite y; + + y = M * x; + + WOLF_DEBUG("y = M * x = " , y); + +} + +TEST(MatrixComposite, productMatrix) +{ + unsigned int psize, osize, vsize; + psize = 2; + osize = 1; + vsize = 2; + + MatrixComposite M, N; + + MatrixXd Mpp(psize,psize), Mpo(psize, osize), Mop(osize,psize), Moo(osize,osize); + Mpp.setOnes(); + Mpo.setOnes(); Mpo *= 2; + Mop.setOnes(); Mop *= 3; + Moo.setOnes(); Moo *= 4; + + M.emplace("P", "P", Mpp); + M.emplace("P", "O", Mpo); + M.emplace("O", "P", Mop); + M.emplace("O", "O", Moo); + WOLF_DEBUG("M = " , M); + + MatrixXd Noo(osize,osize), Nov(osize, vsize), Npo(psize,osize), Npv(psize,vsize); + Noo.setOnes(); + Nov.setOnes(); Nov *= 2; + Npo.setOnes(); Npo *= 3; + Npv.setOnes(); Npv *= 4; + + N.emplace("O", "O", Noo); + N.emplace("O", "V", Nov); + N.emplace("P", "O", Npo); + N.emplace("P", "V", Npv); + WOLF_DEBUG("N = " , N); + + MatrixComposite MN; + + MN = M * N; + + WOLF_DEBUG("MN = M * N = " , MN); + + MatrixXd MNpo(MatrixXd::Ones(psize,osize) * 8); + MatrixXd MNpv(MatrixXd::Ones(psize,vsize) * 12); + MatrixXd MNoo(MatrixXd::Ones(osize,osize) * 22); + MatrixXd MNov(MatrixXd::Ones(osize,vsize) * 32); + + ASSERT_MATRIX_APPROX(MN.at("P","O"), MNpo, 1e-20); + ASSERT_MATRIX_APPROX(MN.at("P","V"), MNpv, 1e-20); + ASSERT_MATRIX_APPROX(MN.at("O","O"), MNoo, 1e-20); + ASSERT_MATRIX_APPROX(MN.at("O","V"), MNov, 1e-20); + +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + + // restrict to a group of tests only + //::testing::GTEST_FLAG(filter) = "TestInit.*"; + + // restrict to this test only + //::testing::GTEST_FLAG(filter) = "TestInit.testName"; + + return RUN_ALL_TESTS(); +}