/* * graph-inl.h * @brief Graph algorithm using boost library * @author: Kai Ni */ #pragma once #include #include #include #include using namespace std; #define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL) namespace gtsam { /* ************************************************************************* */ template class ordering_key_visitor : public boost::default_bfs_visitor { public: ordering_key_visitor(std::list& ordering_in) : ordering_(ordering_in) {} template void discover_vertex(Vertex v, const Graph& g) const { Key key = boost::get(boost::vertex_name, g, v); ordering_.push_front(key); } std::list& ordering_; }; /* ************************************************************************* */ template list predecessorMap2Keys(const PredecessorMap& p_map) { typedef typename SGraph::Vertex SVertex; SGraph g; SVertex root; std::map key2vertex; boost::tie(g, root, key2vertex) = gtsam::predecessorMap2Graph, SVertex, Key>(p_map); // breadth first visit on the graph std::list keys; ordering_key_visitor vis(keys); boost::breadth_first_search(g, root, boost::visitor(vis)); return keys; } ///* ************************************************************************* */ //template // SL-NEEDED? SDGraph toBoostGraph(const G& graph) { // // convert the factor graph to boost graph // SDGraph g; // typedef typename boost::graph_traits >::vertex_descriptor BoostVertex; // map key2vertex; // BoostVertex v1, v2; // typename G::const_iterator itFactor; // for(itFactor=graph.begin(); itFactor!=graph.end(); itFactor++) { // if ((*itFactor)->keys().size() > 2) // throw(invalid_argument("toBoostGraph: only support factors with at most two keys")); // // if ((*itFactor)->keys().size() == 1) // continue; // // boost::shared_ptr factor = boost::dynamic_pointer_cast(*itFactor); // if (!factor) continue; // // Key key1 = factor->key1(); // Key key2 = factor->key2(); // // if (key2vertex.find(key1) == key2vertex.end()) { // v1 = add_vertex(key1, g); // key2vertex.insert(make_pair(key1, v1)); // } else // v1 = key2vertex[key1]; // // if (key2vertex.find(key2) == key2vertex.end()) { // v2 = add_vertex(key2, g); // key2vertex.insert(make_pair(key2, v2)); // } else // v2 = key2vertex[key2]; // // boost::property edge_property(1.0); // assume constant edge weight here // boost::add_edge(v1, v2, edge_property, g); // } // // return g; //} /* ************************************************************************* */ template boost::tuple > predecessorMap2Graph(const PredecessorMap& p_map) { G g; map key2vertex; V v1, v2, root; Key child, parent; bool foundRoot = false; FOREACH_PAIR(child, parent, p_map) { if (key2vertex.find(child) == key2vertex.end()) { v1 = add_vertex(child, g); key2vertex.insert(make_pair(child, v1)); } else v1 = key2vertex[child]; if (key2vertex.find(parent) == key2vertex.end()) { v2 = add_vertex(parent, g); key2vertex.insert(make_pair(parent, v2)); } else v2 = key2vertex[parent]; if (child==parent) { root = v1; foundRoot = true; } else boost::add_edge(v2, v1, g); // edge is from parent to child } if (!foundRoot) throw invalid_argument("predecessorMap2Graph: invalid predecessor map!"); else return boost::tuple >(g, root, key2vertex); } /* ************************************************************************* */ template class compose_key_visitor : public boost::default_bfs_visitor { private: boost::shared_ptr config_; public: compose_key_visitor(boost::shared_ptr config_in) {config_ = config_in;} template void tree_edge(Edge edge, const Graph& g) const { typename Values::Key key_from = boost::get(boost::vertex_name, g, boost::source(edge, g)); typename Values::Key key_to = boost::get(boost::vertex_name, g, boost::target(edge, g)); Pose relativePose = boost::get(boost::edge_weight, g, edge); config_->insert(key_to, (*config_)[key_from].compose(relativePose)); } }; /* ************************************************************************* */ template boost::shared_ptr composePoses(const G& graph, const PredecessorMap& tree, const Pose& rootPose) { //TODO: change edge_weight_t to edge_pose_t typedef typename boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, boost::property, boost::property > PoseGraph; typedef typename boost::graph_traits::vertex_descriptor PoseVertex; typedef typename boost::graph_traits::edge_descriptor PoseEdge; PoseGraph g; PoseVertex root; map key2vertex; boost::tie(g, root, key2vertex) = predecessorMap2Graph(tree); // attach the relative poses to the edges PoseEdge edge12, edge21; bool found1, found2; BOOST_FOREACH(typename G::sharedFactor nl_factor, graph) { if (nl_factor->keys().size() > 2) throw invalid_argument("composePoses: only support factors with at most two keys"); // e.g. in pose2graph, nonlinear factor needs to be converted to pose2factor boost::shared_ptr factor = boost::dynamic_pointer_cast(nl_factor); if (!factor) continue; typename Values::Key key1 = factor->key1(); typename Values::Key key2 = factor->key2(); PoseVertex v1 = key2vertex.find(key1)->second; PoseVertex v2 = key2vertex.find(key2)->second; Pose l1Xl2 = factor->measured(); tie(edge12, found1) = boost::edge(v1, v2, g); tie(edge21, found2) = boost::edge(v2, v1, g); if (found1 && found2) throw invalid_argument ("composePoses: invalid spanning tree"); if (!found1 && !found2) continue; if (found1) boost::put(boost::edge_weight, g, edge12, l1Xl2); else if (found2) boost::put(boost::edge_weight, g, edge21, l1Xl2.inverse()); } // compose poses boost::shared_ptr config(new Values); typename Values::Key rootKey = boost::get(boost::vertex_name, g, root); config->insert(rootKey, rootPose); compose_key_visitor vis(config); boost::breadth_first_search(g, root, boost::visitor(vis)); return config; } /* ************************************************************************* */ }