gtsam  3.2.1
gtsam
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
graph-inl.h
1 /* ----------------------------------------------------------------------------
2 
3  * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4  * Atlanta, Georgia 30332-0415
5  * All Rights Reserved
6  * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7 
8  * See LICENSE for the license information
9 
10  * -------------------------------------------------------------------------- */
11 
12 /*
13  * @file graph-inl.h
14  * @brief Graph algorithm using boost library
15  * @author Kai Ni
16  */
17 
18 #pragma once
19 
20 #include <stdexcept>
21 #include <boost/foreach.hpp>
22 #ifdef __GNUC__
23 #pragma GCC diagnostic push
24 #pragma GCC diagnostic ignored "-Wunused-variable"
25 //#pragma GCC diagnostic ignored "-Wunneeded-internal-declaration"
26 #endif
27 #include <boost/graph/breadth_first_search.hpp>
28 #ifdef __GNUC__
29 #pragma GCC diagnostic pop
30 #endif
31 #include <boost/graph/prim_minimum_spanning_tree.hpp>
32 
33 #include <gtsam/inference/graph.h>
34 
35 #define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL)
36 
37 namespace gtsam {
38 
39 /* ************************************************************************* */
40 template <class KEY>
41 class ordering_key_visitor : public boost::default_bfs_visitor {
42 public:
43  ordering_key_visitor(std::list<KEY>& ordering_in) : ordering_(ordering_in) {}
44  template <typename Vertex, typename Graph> void discover_vertex(Vertex v, const Graph& g) const {
45  KEY key = boost::get(boost::vertex_name, g, v);
46  ordering_.push_front(key);
47  }
48  std::list<KEY>& ordering_;
49 };
50 
51 /* ************************************************************************* */
52 template<class KEY>
53 std::list<KEY> predecessorMap2Keys(const PredecessorMap<KEY>& p_map) {
54 
55  typedef typename SGraph<KEY>::Vertex SVertex;
56 
57  SGraph<KEY> g;
58  SVertex root;
59  std::map<KEY, SVertex> key2vertex;
60  boost::tie(g, root, key2vertex) = gtsam::predecessorMap2Graph<SGraph<KEY>, SVertex, KEY>(p_map);
61 
62  // breadth first visit on the graph
63  std::list<KEY> keys;
64  ordering_key_visitor<KEY> vis(keys);
65  boost::breadth_first_search(g, root, boost::visitor(vis));
66  return keys;
67 }
68 
69 /* ************************************************************************* */
70 template<class G, class F, class KEY>
71 SDGraph<KEY> toBoostGraph(const G& graph) {
72  // convert the factor graph to boost graph
73  SDGraph<KEY> g;
74  typedef typename boost::graph_traits<SDGraph<KEY> >::vertex_descriptor BoostVertex;
75  std::map<KEY, BoostVertex> key2vertex;
76  typename G::const_iterator itFactor;
77 
78  // Loop over the factors
79  for(itFactor=graph.begin(); itFactor!=graph.end(); itFactor++) {
80 
81  // Ignore factors that are not binary
82  if ((*itFactor)->keys().size() != 2)
83  continue;
84 
85  // Cast the factor to the user-specified factor type F
86  boost::shared_ptr<F> factor = boost::dynamic_pointer_cast<F>(*itFactor);
87  // Ignore factors that are not of type F
88  if (!factor) continue;
89 
90  // Retrieve the 2 keys (nodes) the factor (edge) is incident on
91  KEY key1 = factor->keys()[0];
92  KEY key2 = factor->keys()[1];
93 
94  BoostVertex v1, v2;
95 
96  // If key1 is a new key, add it to the key2vertex map, else get the corresponding vertex id
97  if (key2vertex.find(key1) == key2vertex.end()) {
98  v1 = add_vertex(key1, g);
99  key2vertex.insert(std::pair<KEY,KEY>(key1, v1));
100  } else
101  v1 = key2vertex[key1];
102 
103  // If key2 is a new key, add it to the key2vertex map, else get the corresponding vertex id
104  if (key2vertex.find(key2) == key2vertex.end()) {
105  v2 = add_vertex(key2, g);
106  key2vertex.insert(std::pair<KEY,KEY>(key2, v2));
107  } else
108  v2 = key2vertex[key2];
109 
110  // Add an edge with weight 1.0
111  boost::property<boost::edge_weight_t, double> edge_property(1.0); // assume constant edge weight here
112  boost::add_edge(v1, v2, edge_property, g);
113  }
114 
115  return g;
116 }
117 
118 /* ************************************************************************* */
119 template<class G, class V, class KEY>
120 boost::tuple<G, V, std::map<KEY,V> >
122 
123  G g;
124  std::map<KEY, V> key2vertex;
125  V v1, v2, root;
126  KEY child, parent;
127  bool foundRoot = false;
128  FOREACH_PAIR(child, parent, p_map) {
129  if (key2vertex.find(child) == key2vertex.end()) {
130  v1 = add_vertex(child, g);
131  key2vertex.insert(std::make_pair(child, v1));
132  } else
133  v1 = key2vertex[child];
134 
135  if (key2vertex.find(parent) == key2vertex.end()) {
136  v2 = add_vertex(parent, g);
137  key2vertex.insert(std::make_pair(parent, v2));
138  } else
139  v2 = key2vertex[parent];
140 
141  if (child==parent) {
142  root = v1;
143  foundRoot = true;
144  } else
145  boost::add_edge(v2, v1, g); // edge is from parent to child
146  }
147 
148  if (!foundRoot)
149  throw std::invalid_argument("predecessorMap2Graph: invalid predecessor map!");
150  else
151  return boost::tuple<G, V, std::map<KEY, V> >(g, root, key2vertex);
152 }
153 
154 /* ************************************************************************* */
155 template <class V, class POSE, class KEY>
156 class compose_key_visitor : public boost::default_bfs_visitor {
157 
158 private:
159  boost::shared_ptr<Values> config_;
160 
161 public:
162 
163  compose_key_visitor(boost::shared_ptr<Values> config_in) {config_ = config_in;}
164 
165  template <typename Edge, typename Graph> void tree_edge(Edge edge, const Graph& g) const {
166  KEY key_from = boost::get(boost::vertex_name, g, boost::source(edge, g));
167  KEY key_to = boost::get(boost::vertex_name, g, boost::target(edge, g));
168  POSE relativePose = boost::get(boost::edge_weight, g, edge);
169  config_->insert(key_to, config_->at<POSE>(key_from).compose(relativePose));
170  }
171 
172 };
173 
174 /* ************************************************************************* */
175 template<class G, class Factor, class POSE, class KEY>
176 boost::shared_ptr<Values> composePoses(const G& graph, const PredecessorMap<KEY>& tree,
177  const POSE& rootPose) {
178 
179  //TODO: change edge_weight_t to edge_pose_t
180  typedef typename boost::adjacency_list<
181  boost::vecS, boost::vecS, boost::directedS,
182  boost::property<boost::vertex_name_t, KEY>,
183  boost::property<boost::edge_weight_t, POSE> > PoseGraph;
184  typedef typename boost::graph_traits<PoseGraph>::vertex_descriptor PoseVertex;
185  typedef typename boost::graph_traits<PoseGraph>::edge_descriptor PoseEdge;
186 
187  PoseGraph g;
188  PoseVertex root;
189  std::map<KEY, PoseVertex> key2vertex;
190  boost::tie(g, root, key2vertex) =
191  predecessorMap2Graph<PoseGraph, PoseVertex, KEY>(tree);
192 
193  // attach the relative poses to the edges
194  PoseEdge edge12, edge21;
195  bool found1, found2;
196  BOOST_FOREACH(typename G::sharedFactor nl_factor, graph) {
197 
198  if (nl_factor->keys().size() > 2)
199  throw std::invalid_argument("composePoses: only support factors with at most two keys");
200 
201  // e.g. in pose2graph, nonlinear factor needs to be converted to pose2factor
202  boost::shared_ptr<Factor> factor = boost::dynamic_pointer_cast<Factor>(nl_factor);
203  if (!factor) continue;
204 
205  KEY key1 = factor->key1();
206  KEY key2 = factor->key2();
207 
208  PoseVertex v1 = key2vertex.find(key1)->second;
209  PoseVertex v2 = key2vertex.find(key2)->second;
210 
211  POSE l1Xl2 = factor->measured();
212  boost::tie(edge12, found1) = boost::edge(v1, v2, g);
213  boost::tie(edge21, found2) = boost::edge(v2, v1, g);
214  if (found1 && found2) throw std::invalid_argument ("composePoses: invalid spanning tree");
215  if (!found1 && !found2) continue;
216  if (found1)
217  boost::put(boost::edge_weight, g, edge12, l1Xl2);
218  else if (found2)
219  boost::put(boost::edge_weight, g, edge21, l1Xl2.inverse());
220  }
221 
222  // compose poses
223  boost::shared_ptr<Values> config(new Values);
224  KEY rootKey = boost::get(boost::vertex_name, g, root);
225  config->insert(rootKey, rootPose);
227  boost::breadth_first_search(g, root, boost::visitor(vis));
228 
229  return config;
230 }
231 
232 /* ************************************************************************* */
233 template<class G, class KEY, class FACTOR2>
235 
236  // Convert to a graph that boost understands
237  SDGraph<KEY> g = gtsam::toBoostGraph<G, FACTOR2, KEY>(fg);
238 
239  // find minimum spanning tree
240  std::vector<typename SDGraph<KEY>::Vertex> p_map(boost::num_vertices(g));
241  prim_minimum_spanning_tree(g, &p_map[0]);
242 
243  // convert edge to string pairs
244  PredecessorMap<KEY> tree;
245  typename SDGraph<KEY>::vertex_iterator itVertex = boost::vertices(g).first;
246  BOOST_FOREACH(const typename SDGraph<KEY>::Vertex& vi, p_map){
247  KEY key = boost::get(boost::vertex_name, g, *itVertex);
248  KEY parent = boost::get(boost::vertex_name, g, vi);
249  tree.insert(key, parent);
250  itVertex++;
251  }
252  return tree;
253 }
254 
255 /* ************************************************************************* */
256 template<class G, class KEY, class FACTOR2>
257 void split(const G& g, const PredecessorMap<KEY>& tree, G& Ab1, G& Ab2) {
258 
259  typedef typename G::sharedFactor F ;
260 
261  BOOST_FOREACH(const F& factor, g)
262  {
263  if (factor->keys().size() > 2)
264  throw(std::invalid_argument("split: only support factors with at most two keys"));
265 
266  if (factor->keys().size() == 1) {
267  Ab1.push_back(factor);
268  continue;
269  }
270 
271  boost::shared_ptr<FACTOR2> factor2 = boost::dynamic_pointer_cast<
272  FACTOR2>(factor);
273  if (!factor2) continue;
274 
275  KEY key1 = factor2->key1();
276  KEY key2 = factor2->key2();
277  // if the tree contains the key
278  if ((tree.find(key1) != tree.end() &&
279  tree.find(key1)->second.compare(key2) == 0) ||
280  (tree.find(key2) != tree.end() &&
281  tree.find(key2)->second.compare(key1)== 0) )
282  Ab1.push_back(factor2);
283  else
284  Ab2.push_back(factor2);
285  }
286 }
287 
288 }
boost::tuple< G, V, std::map< KEY, V > > predecessorMap2Graph(const PredecessorMap< KEY > &p_map)
Build takes a predecessor map, and builds a directed graph corresponding to the tree.
Definition: graph-inl.h:121
SDGraph is undirected graph with variable keys and double edge weights.
Definition: graph.h:38
PredecessorMap< KEY > findMinimumSpanningTree(const G &fg)
find the minimum spanning tree using boost graph library
Definition: graph-inl.h:234
Map from variable key to parent key.
Definition: graph.h:58
boost::shared_ptr< Values > composePoses(const G &graph, const PredecessorMap< KEY > &tree, const POSE &rootPose)
Compose the poses by following the chain specified by the spanning tree.
Definition: graph-inl.h:176
This is the base class for all factor types.
Definition: Factor.h:51
Graph algorithm using boost library.
Definition: graph-inl.h:41
A non-templated config holding any types of Manifold-group elements.
Definition: Values.h:75
Definition: graph.h:46
std::list< KEY > predecessorMap2Keys(const PredecessorMap< KEY > &p_map)
Generate a list of keys from a spanning tree represented by its predecessor map.
Definition: graph-inl.h:53
Definition: graph-inl.h:156
void insert(const KEY &key, const KEY &parent)
convenience insert so we can pass ints for TypedSymbol keys
Definition: graph.h:61
SDGraph< KEY > toBoostGraph(const G &graph)
Convert the factor graph to an SDGraph G = Graph type F = Factor type Key = Key type.
Definition: graph-inl.h:71
void split(const G &g, const PredecessorMap< KEY > &tree, G &Ab1, G &Ab2)
Split the graph into two parts: one corresponds to the given spanning tree, and the other corresponds...
Definition: graph-inl.h:257