Main MRPT website > C++ reference
MRPT logo
spantree_update_symbolic.h
Go to the documentation of this file.
1 /* +---------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2015, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +---------------------------------------------------------------------------+ */
9 
10 #pragma once
11 
12 namespace mrpt { namespace srba {
13 
14 
15 #define SYM_ST_SUPER_VERBOSE 0
16 
17 /** Incremental update of spanning trees after the insertion of ONE new node and ONE OR MORE edges */
18 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
20  const TKeyFrameID new_node_id,
21  const TPairKeyFrameID & new_edge,
22  const topo_dist_t max_depth,
23  const bool check_all_obs_are_connected,
24  const new_kf_observations_t * obs
25  )
26 {
27  using namespace std;
28  ASSERT_(max_depth>=1)
29 
30  // Maintain a list of those nodes whose list of shortest spanning trees ("next_edge") has been modified, so we
31  // can rebuild their "all_edges" lists.
32  std::set<TPairKeyFrameID> kfs_with_modified_next_edge;
33 
34  // Generic algorithm for 1 or more new edges at once from the new_kf_id to the rest of the graph:
35  // -----------------------------------------------------------------------------------------------
36  // The first edge was already introduced in the STs above. Go on with the rest:
37  // (Notation is according to the ICRA2013 paper, see explanatory graphs or understanding this is a hell!! ;-)
38  {
39  //const TKeyFrameID ik = getTheOtherFromPair(new_node_id, new_edges[nE] );
40  const TKeyFrameID ik = getTheOtherFromPair(new_node_id, new_edge );
41 
42  // Build set tk = all nodes within distance <=(max_depth-1) from "ik"
43  const map<TKeyFrameID,TSpanTreeEntry> & st_ik = sym.next_edge[ik]; // O(1)
44  vector<pair<TKeyFrameID,topo_dist_t> > tk;
45  for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=st_ik.begin();it!=st_ik.end();++it)
46  if (it->second.distance<max_depth)
47  tk.push_back( make_pair(it->first,it->second.distance) );
48  tk.push_back( make_pair(ik,0) ); // The set includes the root itself, which is not in the STs structures.
49 
50  // Build set STn = all nodes within distance <=max_depth from "new_node_id"
51  // This will also CREATE the empty ST for "new_node_id" upon first call to [], in amortized O(1)
52  const map<TKeyFrameID,TSpanTreeEntry> & st_n = sym.next_edge[new_node_id]; // access O(1)
53  vector<pair<TKeyFrameID,const TSpanTreeEntry*> > STn;
54  for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=st_n.begin();it!=st_n.end();++it)
55  STn.push_back( make_pair(it->first,&it->second) );
56  STn.push_back( pair<TKeyFrameID,const TSpanTreeEntry*>(new_node_id,static_cast<const TSpanTreeEntry*>(NULL)) ); // The set includes the root itself, which is not in the STs structures.
57 
58  // for each r \in ST_W(n)
59  for (size_t r_idx=0;r_idx<STn.size();r_idx++)
60  {
61  const TKeyFrameID r = STn[r_idx].first;
62  const TSpanTreeEntry * ste_n2r = STn[r_idx].second;
63  const topo_dist_t dist_r2n = ste_n2r ? ste_n2r->distance : 0;
64 
65  map<TKeyFrameID,TSpanTreeEntry> & st_r = sym.next_edge[r]; // O(1)
66 
67  TSpanTreeEntry * ste_r2n = NULL; // Will stay NULL for r=new_node_id
68  if (r!=new_node_id)
69  {
70  map<TKeyFrameID,TSpanTreeEntry>::iterator it = st_r.find(new_node_id);
71  ASSERT_(it!=st_r.end())
72  ste_r2n = &it->second;
73  }
74 
75  // for each s \in ST_{W-1}(i_k)
76  for (size_t s_idx=0;s_idx<tk.size();s_idx++)
77  {
78  const TKeyFrameID s = tk[s_idx].first;
79  if (r==s) continue;
80  const topo_dist_t dist_s2ik = tk[s_idx].second;
81 
82  map<TKeyFrameID,TSpanTreeEntry> & st_s = sym.next_edge[s]; // O(1)
83 
84  TSpanTreeEntry *ste_s2ik=NULL; // =NULL if s==ik
85  if (s!=ik)
86  {
87  map<TKeyFrameID,TSpanTreeEntry>::iterator it_ik_inSTs = st_s.find(ik);
88  ASSERTDEB_(it_ik_inSTs != st_s.end())
89  ste_s2ik = &it_ik_inSTs->second;
90  }
91 
92  // new tentative distance s <--> ik
93  const topo_dist_t new_dist = dist_r2n + dist_s2ik + 1;
94 
95  // Is s \in ST(r)?
96  map<TKeyFrameID,TSpanTreeEntry>::iterator it_s_inSTr = st_r.find(s); // O(log N)
97  if (it_s_inSTr != st_r.end())
98  { // Found:
99  // Is it shorter to go (r)->(n)--[dist=1]-->(ik)->(s) than (r)->(s) ? Then modify spanning tree
100  if (new_dist < it_s_inSTr->second.distance)
101  {
102 #if SYM_ST_SUPER_VERBOSE
103 cout << "ST: Shorter path ST["<<r<<"]["<<s<<"].N was "<<it_s_inSTr->second.next << " => "<<(ste_r2n ? ste_r2n->next : ik) << "[D:"<<it_s_inSTr->second.distance<<"=>"<<new_dist<<"]"<<endl;
104 cout << "ST: Shorter path ST["<<s<<"]["<<r<<"].N was "<<st_s[r].next << " => "<<(ste_s2ik ? ste_s2ik->next : new_node_id) << "[D:"<<st_s[r].distance<<"=>"<<new_dist<<"]"<<endl;
105 #endif
106  // It's shorter: change spanning tree
107  // ST[r][s]
108  it_s_inSTr->second.distance = new_dist;
109  it_s_inSTr->second.next = ste_r2n ? ste_r2n->next : ik; // Next node in the direction towards "new_node_id"
110  ASSERT_NOT_EQUAL_(r,it_s_inSTr->second.next) // no self-loops!
111 
112  // ST[s][r]
113  TSpanTreeEntry &ste_r_inSTs = st_s[r];
114  ste_r_inSTs.distance = new_dist;
115  ste_r_inSTs.next = ste_s2ik ? ste_s2ik->next : new_node_id; // Next node in the direction towards "ik" or to "n" if this is "ik"
116  ASSERT_NOT_EQUAL_(s,ste_r_inSTs.next) // no self-loops!
117 
118  // Mark nodes with their "next_node" modified:
119  kfs_with_modified_next_edge.insert( make_pair(s,r) );
120  kfs_with_modified_next_edge.insert( make_pair(r,s) );
121  }
122  // Otherwise, leave things stay.
123  }
124  else
125  { // Not found:
126  if (new_dist<=max_depth)
127  {
128 #if SYM_ST_SUPER_VERBOSE
129 cout << "ST: New path ST["<<r<<"]["<<s<<"].N ="<<(ste_r2n ? ste_r2n->next : ik) << "[D:"<<dist_r2n + dist_s2ik + 1<<"]"<<endl;
130 cout << "ST: New path ST["<<s<<"]["<<r<<"].N ="<<(ste_s2ik ? ste_s2ik->next : new_node_id) << "[D:"<<dist_r2n + dist_s2ik + 1<<"]"<<endl;
131 #endif
132 
133  // Then the node "s" wasn't reachable from "r" but now it is:
134  // ST[r][s]
135  TSpanTreeEntry &ste_s_inSTr = st_r[s]; // O(log N)
136 
137  ste_s_inSTr.distance = new_dist;
138  ste_s_inSTr.next = ste_r2n ? ste_r2n->next : ik; // Next node in the direction towards "new_node_id"
139  ASSERT_NOT_EQUAL_(r,ste_s_inSTr.next) // no self-loops!
140 
141  // ST[s][r]
142  TSpanTreeEntry &ste_r_inSTs = st_s[r]; // O(log N)
143  ste_r_inSTs.distance = new_dist;
144  ste_r_inSTs.next = ste_s2ik ? ste_s2ik->next : new_node_id; // Next node in the direction towards "ik"
145  ASSERT_NOT_EQUAL_(s, ste_r_inSTs.next) // no self-loops!
146 
147  // Mark nodes with their "next_node" modified:
148  kfs_with_modified_next_edge.insert(make_pair(r,s));
149  kfs_with_modified_next_edge.insert(make_pair(s,r));
150  }
151  }
152 
153  } // end for each s
154  } // end for each r
155 
156  } // end for each new edge
157 
158 
159  // Optional check for correct connection of observed base KFs to current KF -------------
160  if (check_all_obs_are_connected)
161  {
162  ASSERT_(obs)
163 
164  // 1) Build a first list of pending spanning trees to build from observations:
165  std::set<TPairKeyFrameID> pending_checks;
166 
167  for (size_t i=0;i<obs->size();i++)
168  {
169  const new_kf_observation_t &o = (*obs)[i];
170 
171  // If it's a new Landmark (observed for the first time, already not added to the data structures), just skip
172  // since we won't need spanning trees for it.
173  if (o.obs.feat_id>=m_parent->all_lms.size() || m_parent->all_lms[ o.obs.feat_id ].rfp==NULL)
174  continue;
175 
176  const TKeyFrameID base_id = m_parent->all_lms[ o.obs.feat_id ].rfp->id_frame_base;
177 
178  // make sure a spanning tree exists between "new_node_id" -> "base_id":
179  pending_checks.insert( TPairKeyFrameID( new_node_id, base_id ) );
180  }
181 
182  std::set<TPairKeyFrameID> done_checks;
183  while (!pending_checks.empty())
184  {
185  // Get first one:
186  const TPairKeyFrameID ft = *pending_checks.begin(); // copy, don't make a ref since we're deleting the element in the container!
187  pending_checks.erase(pending_checks.begin());
188 
189  if (done_checks.find(ft)!=done_checks.end())
190  continue; // We already done this one.
191 
192  // Create path:
193  std::map<TKeyFrameID,TSpanTreeEntry> & span_trees_from = sym.next_edge[ft.first];
194 
195  if ( span_trees_from.find(ft.second)==span_trees_from.end() )
196  { // It doesn't exist: create it.
197 
198  // We need the starting edge from "ft.first" in the direction towards "ft.second",
199  // and in the way mark as pending all the edges "intermediary node" -> "ft.second".
200  vector<TKeyFrameID> found_path;
201 
202  bool found = m_parent->find_path_bfs(
203  ft.first, // from
204  ft.second, // target node
205  &found_path);
206 
207  ASSERT_(found && !found_path.empty())
208 
209  // save direction:
210  TSpanTreeEntry & ste = span_trees_from[ft.second];
211  ste.distance = found_path.size();
212  ste.next = *found_path.rbegin(); // the last element
213 
214  // and append the rest of KFs as pending:
215  for (size_t i=0;i<found_path.size();i++)
216  if (found_path[i]!=ft.second)
217  pending_checks.insert( TPairKeyFrameID( found_path[i] , ft.second ) );
218 
219  // Remember to update the node's "all_edges" field:
220  kfs_with_modified_next_edge.insert( ft );
221  }
222 
223  // Mark as done:
224  done_checks.insert(ft);
225  }
226 
227  } // end if "check_all_obs_are_connected"
228 
229 
230 #if defined(SYM_ST_SUPER_VERBOSE_SAVE_ALL_SPANNING_TREES)
231  {
232  static int i=0;
233  const std::string sFil = mrpt::format("debug_spantree_%05i.txt",i);
234  const std::string sFilDot = mrpt::format("debug_spantree_%05i.dot",i);
235  const std::string sFilPng = mrpt::format("debug_spantree_%05i.png",i);
236  this->dump_as_text_to_file(sFil);
237  this->save_as_dot_file(sFilDot);
238  ::system(mrpt::format("dot %s -o %s -Tpng",sFilDot.c_str(), sFilPng.c_str() ).c_str());
239  i++;
240  }
241 #endif
242 
243  // Update "all_edges" --------------------------------------------
244  // Only for those who were really modified.
245  for (std::set<TPairKeyFrameID>::const_iterator it=kfs_with_modified_next_edge.begin();it!=kfs_with_modified_next_edge.end();++it)
246  {
247  const TKeyFrameID kf_id = it->first;
248  const std::map<TKeyFrameID,TSpanTreeEntry> & Ds = sym.next_edge[ kf_id ]; // O(1) in map_as_vector
249 
251  ASSERT_(it2!=Ds.end())
252 
253 
254  const TKeyFrameID dst_kf_id = it2->first;
255 
256  const TKeyFrameID from = std::max(dst_kf_id, kf_id);
257  const TKeyFrameID to = std::min(dst_kf_id, kf_id);
258 
259  // find_path_bfs
260  typename kf2kf_pose_traits<KF2KF_POSE_TYPE>::k2k_edge_vector_t & path = sym.all_edges[from][to]; // O(1) in map_as_vector
261  path.clear();
262  bool path_found = m_parent->find_path_bfs(from,to, NULL, &path);
263  ASSERT_(path_found)
264  } // end for each "kfs_with_modified_next_edge"
265 
266 
267 #if defined(SYM_ST_EXTRA_SECURITY_CHECKS)
268  {
269  // Security check: All spanning trees must have a max. depth of "max_depth"
270  // 1st step: define nodes & their depths:
272  for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=it1->second.begin();it!=it1->second.end();++it)
273  if (it->second.distance>max_depth)
274  {
275  std::stringstream s;
276  s << "CONSISTENCY ERROR: Spanning tree of kf #" << it1->first << " has kf #" << it->first
277  << " at depth=" << it->second.distance << " > Max=" << max_depth << endl;
278  s << "After updating symbolic spanning trees for new kf #" << new_node_id << " with new edges: ";
279  for (size_t i=0;i<new_edges.size();i++) s << new_edges[i].first << "->" << new_edges[i].second << ", ";
280  s << endl;
281  THROW_EXCEPTION(s.str())
282  }
283  }
284 #endif
285 }
286 
287 template <class k2k_edge_t>
288 struct TBFSEntry
289 {
290  TBFSEntry() : prev_edge(NULL),dist( std::numeric_limits<topo_dist_t>::max() )
291  {}
292 
296 };
297 
298 // Aux. function for "check_all_obs_are_connected":
299 // Breadth-first search (BFS) for "trg_node"
300 // Return: true: found
301 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
303  const TKeyFrameID cur_node,
304  const TKeyFrameID trg_node,
305  std::vector<TKeyFrameID> * out_path_IDs,
306  typename kf2kf_pose_traits<KF2KF_POSE_TYPE>::k2k_edge_vector_t * out_path_edges ) const
307 {
308  if (out_path_IDs) out_path_IDs->clear();
309  if (out_path_edges) out_path_edges->clear();
310  if (cur_node==trg_node) return true; // No need to do any search...
311 
312  std::set<TKeyFrameID> visited;
313  std::queue<TKeyFrameID> pending;
314  std::map<TKeyFrameID,TBFSEntry<k2k_edge_t> > preceding;
315 
316  // Insert:
317  pending.push(cur_node);
318  visited.insert(cur_node);
319  preceding[cur_node].dist = 0;
320 
321  while (!pending.empty())
322  {
323  const TKeyFrameID next_kf = pending.front();
324  pending.pop();
325 
326  TBFSEntry<k2k_edge_t> & bfs_data_next = preceding[next_kf];
327  const topo_dist_t cur_dist = bfs_data_next.dist;
328 
329  if (next_kf==trg_node)
330  {
331  // Path found: go thru the path in inverse order:
332  topo_dist_t dist = bfs_data_next.dist;
333  if (out_path_IDs) out_path_IDs->resize(dist);
334  if (out_path_edges) out_path_edges->resize(dist);
335  TKeyFrameID path_node = trg_node;
336  while (path_node != cur_node)
337  {
338  ASSERT_(dist>0)
339  if (out_path_IDs) (*out_path_IDs)[--dist] = path_node;
340 
341  typename std::map<TKeyFrameID,TBFSEntry<k2k_edge_t> >::const_iterator it_prec = preceding.find(path_node);
342  ASSERT_(it_prec != preceding.end())
343  path_node = it_prec->second.prev;
344 
345  if (out_path_edges) (*out_path_edges)[--dist] = it_prec->second.prev_edge;
346  }
347  return true; // End of search
348  }
349 
350  // Get all connections of this node:
351  ASSERTDEB_(next_kf < keyframes.size())
352  const keyframe_info & kfi = keyframes[next_kf];
353 
354  for (size_t i=0;i<kfi.adjacent_k2k_edges.size();i++)
355  {
356  const k2k_edge_t* ed = kfi.adjacent_k2k_edges[i];
357  const TKeyFrameID new_kf = getTheOtherFromPair2(next_kf, *ed);
358  if (!visited.count(new_kf))
359  {
360  pending.push(new_kf);
361  visited.insert(new_kf);
362 
363  TBFSEntry<k2k_edge_t> & p = preceding[new_kf];
364 
365  if (p.dist>cur_dist+1)
366  {
367  p.dist = cur_dist+1;
368  p.prev = next_kf;
369  p.prev_edge = const_cast<k2k_edge_t*>(ed);
370  }
371  }
372  }
373  }
374  return false; // No path found.
375 }
376 
377 } } // end NS
next_edge_maps_t next_edge
Given all interesting spanning tree roots (=SOURCE), this structure holds: map[SOURCE] |-> map[TARGET...
Definition: srba_types.h:529
struct mrpt::srba::TRBA_Problem_state::TSpanningTree::TSpanningTreeSym sym
rba_joint_parameterization_traits_t< KF2KF_POSE_TYPE, LM_TYPE, OBS_TYPE >::new_kf_observations_t new_kf_observations_t
Definition: srba_types.h:486
#define THROW_EXCEPTION(msg)
Scalar * iterator
Definition: eigen_plugins.h:23
kf2kf_pose_traits< KF2KF_POSE_TYPE >::k2k_edge_t k2k_edge_t
Definition: srba_types.h:477
STL namespace.
const Scalar * const_iterator
Definition: eigen_plugins.h:24
Keyframe-to-keyframe edge: an unknown of the problem.
Definition: srba_types.h:82
uint64_t topo_dist_t
Unsigned integral type for topological distances in a graph/tree.
Definition: srba_types.h:33
TKeyFrameID next
The next keyframe in the tree.
Definition: srba_types.h:465
TKeyFrameID prev
The argument "POSE_TRAITS" can be any of those defined in srba/models/kf2kf_poses.h (typically, either kf2kf_poses::SE3 or kf2kf_poses::SE2).
Definition: srba_types.h:50
bool save_as_dot_file(const std::string &sFileName, const std::vector< TKeyFrameID > &kf_roots_to_save=std::vector< TKeyFrameID >()) const
Saves all (or a subset of all) the spanning trees If kf_roots_to_save is left empty, all STs are saved.
void update_symbolic_new_node(const TKeyFrameID new_node_id, const TPairKeyFrameID &new_edge, const topo_dist_t max_depth, const bool check_all_obs_are_connected=false, const new_kf_observations_t *obs=NULL)
Incremental update of spanning trees after the insertion of ONE new node and ONE OR MORE edges...
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
topo_dist_t dist
TBFSEntry()
all_edges_maps_t all_edges
From the previous data, we can build this alternative, more convenient representation: map[SOURCE] |-...
Definition: srba_types.h:537
Used in TRBA_Problem_state.
Definition: srba_types.h:463
V getTheOtherFromPair(const V one, const PAIR &p)
Aux function for getting, from a std::pair, "the other" element which is different to a known given o...
Definition: srba_types.h:185
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
#define ASSERTDEB_(f)
Defines an assertion mechanism - only when compiled in debug.
const TRBA_Problem_state< KF2KF_POSE_TYPE, LM_TYPE, OBS_TYPE, RBA_OPTIONS > * m_parent
Definition: srba_types.h:515
#define ASSERT_NOT_EQUAL_(__A, __B)
std::pair< TKeyFrameID, TKeyFrameID > TPairKeyFrameID
Used to represent the IDs of a directed edge (first –> second)
Definition: srba_types.h:34
bool find_path_bfs(const TKeyFrameID from, const TKeyFrameID to, std::vector< TKeyFrameID > *out_path_IDs, typename kf2kf_pose_traits< KF2KF_POSE_TYPE >::k2k_edge_vector_t *out_path_edges=NULL) const
Auxiliary, brute force (BFS) method for finding the shortest path between any two Keyframes...
#define ASSERT_(f)
k2k_edge_t * prev_edge
keyframe_vector_t keyframes
All key frames (global poses are not included in an RBA problem). Vector indices are "TKeyFrameID" ID...
Definition: srba_types.h:635
Information per key-frame needed for RBA.
Definition: srba_types.h:453
topo_dist_t distance
Remaining distance until the given target from this point.
Definition: srba_types.h:466
bool dump_as_text_to_file(const std::string &sFileName) const
Useful for debugging.
Definition: spantree_misc.h:71
V getTheOtherFromPair2(const V one, const K2K_EDGE &p)
For usage with K2K_EDGE = typename kf2kf_pose_traits::k2k_edge_t.
Definition: srba_types.h:191
uint64_t TKeyFrameID
Numeric IDs for key-frames (KFs)
Definition: srba_types.h:31



Page generated by Doxygen 1.8.9.1 for MRPT 1.3.0 SVN: at Sun Sep 13 03:55:12 UTC 2015