diff --git a/src/utils/graph_search.cpp b/src/utils/graph_search.cpp index f1959a029f8b17b97612e047a6d3a6926c18ac3b..d2876701b84d3acabf5e4e9c761a49570bffc2fe 100644 --- a/src/utils/graph_search.cpp +++ b/src/utils/graph_search.cpp @@ -17,25 +17,40 @@ FactorBasePtrList GraphSearch::computeShortestPath(FrameBasePtr frm1, FrameBasePtr frm2, const unsigned int max_graph_dist) { + //WOLF_INFO("GraphSearch::computeShortestPath: from frame ", frm1->id(), " to frame ", frm2->id()); + std::set<FrameBasePtr> frm_neigs({frm1}); + parents_[frm1] = std::pair<FactorBasePtr,FrameBasePtr>(nullptr, nullptr); unsigned int depth = 0; + //WOLF_INFO(frm1->id()); + while (not frm_neigs.empty()) { frm_neigs = getNeighborFrames(frm_neigs); depth++; + //if (not frm_neigs.empty()) + //{ + // std::string frm_neigs_str(depth, '.'); + // for (auto frm : frm_neigs) + // frm_neigs_str += std::to_string(frm->id()) + std::string(" "); + // WOLF_INFO(frm_neigs_str); + //} + // finish if (frm_neigs.count(frm2) != 0) { + //WOLF_INFO("Frame ", frm2->id(), " found!"); + assert(parents_.count(frm2) != 0); FactorBasePtrList factor_path; - auto prev_frm = frm1; + auto frm_it = frm2; - while (parents_.at(prev_frm).second != frm2) + while (frm_it != frm1) { - factor_path.push_back(parents_.at(prev_frm).first); - prev_frm = parents_.at(prev_frm).second; + factor_path.push_back(parents_.at(frm_it).first); + frm_it = parents_.at(frm_it).second; } return factor_path; @@ -45,6 +60,7 @@ FactorBasePtrList GraphSearch::computeShortestPath(FrameBasePtr frm1, if (max_graph_dist > 0 and depth == max_graph_dist) break; } + //WOLF_INFO("Path to frame ", frm2->id(), " NOT found!"); return FactorBasePtrList(); } @@ -61,10 +77,13 @@ std::set<FrameBasePtr> GraphSearch::getNeighborFrames(const std::set<FrameBasePt // Iterate over all factors_by for (auto && fac_by : facs_by) { + //WOLF_INFO_COND(fac_by, "fac_by: ", fac_by->id()); + //WOLF_INFO_COND(fac_by->getFrame(), "fac_by->getFrame(): ", fac_by->getFrame()->id()); if (fac_by and fac_by->getFrame() and - parents_.count(fac_by->getFrame()) != 0) + parents_.count(fac_by->getFrame()) == 0) { + //WOLF_INFO("registering"); frm_neigs.insert(fac_by->getFrame()); parents_[fac_by->getFrame()] = std::pair<FactorBasePtr,FrameBasePtr>(fac_by, frm); } @@ -76,22 +95,24 @@ std::set<FrameBasePtr> GraphSearch::getNeighborFrames(const std::set<FrameBasePt // Iterate over all factors_own for (auto && fac_own : facs_own) + { + //WOLF_INFO_COND(fac_own, "fac_own: ", fac_own->id()); + //WOLF_INFO_COND(fac_own->getFrameOtherList().empty(), "fac_own->getFrameOtherList() is empty"); if (fac_own and not fac_own->getFrameOtherList().empty()) for (auto frm_other_w : fac_own->getFrameOtherList()) { auto frm_other = frm_other_w.lock(); - if (frm_other and parents_.count(frm_other)) + //WOLF_INFO_COND(frm_other, "frm_other ", frm_other->id()); + if (frm_other and + parents_.count(frm_other) == 0) { + //WOLF_INFO("registering"); frm_neigs.insert(frm_other); parents_[frm_other] = std::pair<FactorBasePtr,FrameBasePtr>(fac_own, frm); } } + } } - // TODO - // get list of factors and "constrained by" factor of each frame - // check that these factors are not in factor_parents_ - // check that frames are not in frames_parents_ ant not in frm_neigs - // store in factor_parents_ and frames_parents and frm_neigs return frm_neigs; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8a5eb8fa3a068dca72974a86bdcdee1fd9453baf..be33df04ad6dc395ec55b63b9de14a4ea73ff904 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -80,6 +80,10 @@ target_link_libraries(gtest_feature_base ${PLUGIN_NAME}) wolf_add_gtest(gtest_frame_base gtest_frame_base.cpp) target_link_libraries(gtest_frame_base ${PLUGIN_NAME}) +# GraphSearch class test +wolf_add_gtest(gtest_graph_search gtest_graph_search.cpp) +target_link_libraries(gtest_graph_search ${PLUGIN_NAME}) + # HasStateBlocks classes test wolf_add_gtest(gtest_has_state_blocks gtest_has_state_blocks.cpp) target_link_libraries(gtest_has_state_blocks ${PLUGIN_NAME}) diff --git a/test/gtest_graph_search.cpp b/test/gtest_graph_search.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9693846e7994bf071a1aed368c99626c2311d43a --- /dev/null +++ b/test/gtest_graph_search.cpp @@ -0,0 +1,225 @@ +/* + * gtest_graph_search.cpp + * + * Created on: Jul, 2021 + * Author: jvallve + */ + +#include "core/utils/utils_gtest.h" + +#include "core/problem/problem.h" +#include "core/capture/capture_void.h" +#include "core/factor/factor_relative_pose_2d.h" +#include "core/utils/graph_search.h" + +#include <iostream> +#include <thread> + +using namespace wolf; +using namespace Eigen; + +class GraphSearchTest : public testing::Test +{ + public: + ProblemPtr problem; + + void SetUp() override + { + problem = Problem::create("PO", 2); + } + + FrameBasePtr emplaceFrame(const TimeStamp& ts) + { + return problem->emplaceFrame(ts, Vector3d::Zero()); + } + + FactorBasePtr createFactor(FrameBasePtr frm1, FrameBasePtr frm2) + { + auto C12 = CaptureBase::emplace<CaptureVoid>(frm2, frm2->getTimeStamp(), nullptr); + auto f12 = FeatureBase::emplace<FeatureBase>(C12, "odom", Vector3d::Zero(), Matrix3d::Identity()); + return FactorBase::emplace<FactorRelativePose2d>(f12, f12, frm1, nullptr, false, TOP_MOTION); + } +}; + +TEST_F(GraphSearchTest, setup) +{ + ASSERT_TRUE(problem->check()); +} + +TEST_F(GraphSearchTest, nonsense11) +{ + auto F1 = emplaceFrame(1); + + auto fac_list = GraphSearch::shortestPath(F1, F1, 10); + + ASSERT_TRUE(fac_list.empty()); +} + +TEST_F(GraphSearchTest, single12) +{ + auto F1 = emplaceFrame(1); + auto F2 = emplaceFrame(2); + auto fac12 = createFactor(F1,F2); + + auto fac_list = GraphSearch::shortestPath(F1, F2, 10); + + ASSERT_EQ(fac_list.size(), 1); + ASSERT_EQ(fac_list.front(), fac12); +} + +TEST_F(GraphSearchTest, single21) +{ + auto F1 = emplaceFrame(1); + auto F2 = emplaceFrame(2); + auto fac12 = createFactor(F1,F2); + + auto fac_list = GraphSearch::shortestPath(F2, F1, 10); + + ASSERT_EQ(fac_list.size(), 1); + ASSERT_EQ(fac_list.front(), fac12); +} + +TEST_F(GraphSearchTest, double12) +{ + auto F1 = emplaceFrame(1); + auto F2 = emplaceFrame(2); + auto fac12 = createFactor(F1,F2); + auto fac12b = createFactor(F1,F2); + + auto fac_list = GraphSearch::shortestPath(F1, F2, 10); + + ASSERT_EQ(fac_list.size(), 1); + ASSERT_TRUE(fac_list.front() == fac12 or fac_list.front() == fac12b); +} + +TEST_F(GraphSearchTest, no_solution12) +{ + auto F1 = emplaceFrame(1); + auto F2 = emplaceFrame(2); + auto F3 = emplaceFrame(3); + auto fac23 = createFactor(F2,F3); + + auto fac_list = GraphSearch::shortestPath(F1, F2, 10); + + ASSERT_TRUE(fac_list.empty()); +} + +TEST_F(GraphSearchTest, no_solution21) +{ + auto F1 = emplaceFrame(1); + auto F2 = emplaceFrame(2); + auto F3 = emplaceFrame(3); + auto fac23 = createFactor(F2,F3); + + auto fac_list = GraphSearch::shortestPath(F2, F1, 10); + + ASSERT_TRUE(fac_list.empty()); +} + +TEST_F(GraphSearchTest, large) +{ + auto F1 = emplaceFrame(1); + auto F2 = emplaceFrame(2); + auto F3 = emplaceFrame(3); + auto F4 = emplaceFrame(4); + auto F5 = emplaceFrame(5); + auto F6 = emplaceFrame(6); + auto F7 = emplaceFrame(7); + auto F8 = emplaceFrame(8); + auto F9 = emplaceFrame(9); + + auto fac12 = createFactor(F1,F2); + auto fac23 = createFactor(F2,F3); + auto fac34 = createFactor(F3,F4); + auto fac45 = createFactor(F4,F5); + auto fac56 = createFactor(F5,F6); + auto fac67 = createFactor(F6,F7); + auto fac78 = createFactor(F7,F8); + auto fac89 = createFactor(F8,F9); + + auto fac_list = GraphSearch::shortestPath(F1, F9, 8); + + ASSERT_EQ(fac_list.size(), 8); + + auto fac_list_2 = GraphSearch::shortestPath(F1, F9, 7); + + ASSERT_EQ(fac_list_2.size(), 0); +} + +TEST_F(GraphSearchTest, large_no_solution) +{ + auto F1 = emplaceFrame(1); + auto F2 = emplaceFrame(2); + auto F3 = emplaceFrame(3); + auto F4 = emplaceFrame(4); + auto F5 = emplaceFrame(5); + auto F6 = emplaceFrame(6); + auto F7 = emplaceFrame(7); + auto F8 = emplaceFrame(8); + auto F9 = emplaceFrame(9); + + auto fac12 = createFactor(F1,F2); + auto fac23 = createFactor(F2,F3); + auto fac34 = createFactor(F3,F4); + auto fac45 = createFactor(F4,F5); + + auto fac67 = createFactor(F6,F7); + auto fac78 = createFactor(F7,F8); + auto fac89 = createFactor(F8,F9); + + auto fac_list = GraphSearch::shortestPath(F1, F9, 10); + + ASSERT_EQ(fac_list.size(), 0); + + auto fac_list_2 = GraphSearch::shortestPath(F9, F1, 10); + + ASSERT_EQ(fac_list_2.size(), 0); +} + +TEST_F(GraphSearchTest, large_dense) +{ + /* ------- --------------- + * | | | | + * 1---2---3---4---5---6---7---8---9 + * | | + * ----------- + */ + + auto F1 = emplaceFrame(1); + auto F2 = emplaceFrame(2); + auto F3 = emplaceFrame(3); + auto F4 = emplaceFrame(4); + auto F5 = emplaceFrame(5); + auto F6 = emplaceFrame(6); + auto F7 = emplaceFrame(7); + auto F8 = emplaceFrame(8); + auto F9 = emplaceFrame(9); + + auto fac12 = createFactor(F1,F2); + auto fac13 = createFactor(F1,F3); + auto fac23 = createFactor(F2,F3); + auto fac34 = createFactor(F3,F4); + auto fac36 = createFactor(F3,F6); + auto fac45 = createFactor(F4,F5); + auto fac56 = createFactor(F5,F6); + auto fac59 = createFactor(F5,F9); + auto fac67 = createFactor(F6,F7); + auto fac78 = createFactor(F7,F8); + auto fac89 = createFactor(F8,F9); + + auto fac_list = GraphSearch::shortestPath(F1, F9, 10); + + ASSERT_EQ(fac_list.size(), 4); + + auto fac_list_2 = GraphSearch::shortestPath(F9, F1, 10); + + ASSERT_EQ(fac_list_2.size(), 4); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +