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-2014, 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 using namespace std;
18 
19 /** Incremental update of spanning trees after the insertion of ONE new node and ONE OR MORE edges */
20 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
22  const TKeyFrameID new_node_id,
23  const TPairKeyFrameID & new_edge,
24  const topo_dist_t max_depth,
25  const bool check_all_obs_are_connected,
26  const new_kf_observations_t * obs
27  )
28 {
29  ASSERT_(max_depth>=1)
30 
31  // Maintain a list of those nodes whose list of shortest spanning trees ("next_edge") has been modified, so we
32  // can rebuild their "all_edges" lists.
33  std::set<TPairKeyFrameID> kfs_with_modified_next_edge;
34 
35  // Generic algorithm for 1 or more new edges at once from the new_kf_id to the rest of the graph:
36  // -----------------------------------------------------------------------------------------------
37  // The first edge was already introduced in the STs above. Go on with the rest:
38  // (Notation is according to the ICRA2013 paper, see explanatory graphs or understanding this is a hell!! ;-)
39  {
40  //const TKeyFrameID ik = getTheOtherFromPair(new_node_id, new_edges[nE] );
41  const TKeyFrameID ik = getTheOtherFromPair(new_node_id, new_edge );
42 
43  // Build set tk = all nodes within distance <=(max_depth-1) from "ik"
44  const map<TKeyFrameID,TSpanTreeEntry> & st_ik = sym.next_edge[ik]; // O(1)
45  vector<pair<TKeyFrameID,topo_dist_t> > tk;
46  for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=st_ik.begin();it!=st_ik.end();++it)
47  if (it->second.distance<max_depth)
48  tk.push_back( make_pair(it->first,it->second.distance) );
49  tk.push_back( make_pair(ik,0) ); // The set includes the root itself, which is not in the STs structures.
50 
51  // Build set STn = all nodes within distance <=max_depth from "new_node_id"
52  // This will also CREATE the empty ST for "new_node_id" upon first call to [], in amortized O(1)
53  const map<TKeyFrameID,TSpanTreeEntry> & st_n = sym.next_edge[new_node_id]; // access O(1)
54  vector<pair<TKeyFrameID,const TSpanTreeEntry*> > STn;
55  for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=st_n.begin();it!=st_n.end();++it)
56  STn.push_back( make_pair(it->first,&it->second) );
57  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.
58 
59  // for each r \in ST_W(n)
60  for (size_t r_idx=0;r_idx<STn.size();r_idx++)
61  {
62  const TKeyFrameID r = STn[r_idx].first;
63  const TSpanTreeEntry * ste_n2r = STn[r_idx].second;
64  const topo_dist_t dist_r2n = ste_n2r ? ste_n2r->distance : 0;
65 
66  map<TKeyFrameID,TSpanTreeEntry> & st_r = sym.next_edge[r]; // O(1)
67 
68  TSpanTreeEntry * ste_r2n = NULL; // Will stay NULL for r=new_node_id
69  if (r!=new_node_id)
70  {
71  map<TKeyFrameID,TSpanTreeEntry>::iterator it = st_r.find(new_node_id);
72  ASSERT_(it!=st_r.end())
73  ste_r2n = &it->second;
74  }
75 
76  // for each s \in ST_{W-1}(i_k)
77  for (size_t s_idx=0;s_idx<tk.size();s_idx++)
78  {
79  const TKeyFrameID s = tk[s_idx].first;
80  if (r==s) continue;
81  const topo_dist_t dist_s2ik = tk[s_idx].second;
82 
83  map<TKeyFrameID,TSpanTreeEntry> & st_s = sym.next_edge[s]; // O(1)
84 
85  TSpanTreeEntry *ste_s2ik=NULL; // =NULL if s==ik
86  if (s!=ik)
87  {
88  map<TKeyFrameID,TSpanTreeEntry>::iterator it_ik_inSTs = st_s.find(ik);
89  ASSERTDEB_(it_ik_inSTs != st_s.end())
90  ste_s2ik = &it_ik_inSTs->second;
91  }
92 
93  // new tentative distance s <--> ik
94  const topo_dist_t new_dist = dist_r2n + dist_s2ik + 1;
95 
96  // Is s \in ST(r)?
97  map<TKeyFrameID,TSpanTreeEntry>::iterator it_s_inSTr = st_r.find(s); // O(log N)
98  if (it_s_inSTr != st_r.end())
99  { // Found:
100  // Is it shorter to go (r)->(n)--[dist=1]-->(ik)->(s) than (r)->(s) ? Then modify spanning tree
101  if (new_dist < it_s_inSTr->second.distance)
102  {
103 #if SYM_ST_SUPER_VERBOSE
104 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;
105 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;
106 #endif
107  // It's shorter: change spanning tree
108  // ST[r][s]
109  it_s_inSTr->second.distance = new_dist;
110  it_s_inSTr->second.next = ste_r2n ? ste_r2n->next : ik; // Next node in the direction towards "new_node_id"
111  ASSERT_NOT_EQUAL_(r,it_s_inSTr->second.next) // no self-loops!
112 
113  // ST[s][r]
114  TSpanTreeEntry &ste_r_inSTs = st_s[r];
115  ste_r_inSTs.distance = new_dist;
116  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"
117  ASSERT_NOT_EQUAL_(s,ste_r_inSTs.next) // no self-loops!
118 
119  // Mark nodes with their "next_node" modified:
120  kfs_with_modified_next_edge.insert( make_pair(s,r) );
121  kfs_with_modified_next_edge.insert( make_pair(r,s) );
122  }
123  // Otherwise, leave things stay.
124  }
125  else
126  { // Not found:
127  if (new_dist<=max_depth)
128  {
129 #if SYM_ST_SUPER_VERBOSE
130 cout << "ST: New path ST["<<r<<"]["<<s<<"].N ="<<(ste_r2n ? ste_r2n->next : ik) << "[D:"<<dist_r2n + dist_s2ik + 1<<"]"<<endl;
131 cout << "ST: New path ST["<<s<<"]["<<r<<"].N ="<<(ste_s2ik ? ste_s2ik->next : new_node_id) << "[D:"<<dist_r2n + dist_s2ik + 1<<"]"<<endl;
132 #endif
133 
134  // Then the node "s" wasn't reachable from "r" but now it is:
135  // ST[r][s]
136  TSpanTreeEntry &ste_s_inSTr = st_r[s]; // O(log N)
137 
138  ste_s_inSTr.distance = new_dist;
139  ste_s_inSTr.next = ste_r2n ? ste_r2n->next : ik; // Next node in the direction towards "new_node_id"
140  ASSERT_NOT_EQUAL_(r,ste_s_inSTr.next) // no self-loops!
141 
142  // ST[s][r]
143  TSpanTreeEntry &ste_r_inSTs = st_s[r]; // O(log N)
144  ste_r_inSTs.distance = new_dist;
145  ste_r_inSTs.next = ste_s2ik ? ste_s2ik->next : new_node_id; // Next node in the direction towards "ik"
146  ASSERT_NOT_EQUAL_(s, ste_r_inSTs.next) // no self-loops!
147 
148  // Mark nodes with their "next_node" modified:
149  kfs_with_modified_next_edge.insert(make_pair(r,s));
150  kfs_with_modified_next_edge.insert(make_pair(s,r));
151  }
152  }
153 
154  } // end for each s
155  } // end for each r
156 
157  } // end for each new edge
158 
159 
160  // Optional check for correct connection of observed base KFs to current KF -------------
161  if (check_all_obs_are_connected)
162  {
163  ASSERT_(obs)
164 
165  // 1) Build a first list of pending spanning trees to build from observations:
166  std::set<TPairKeyFrameID> pending_checks;
167 
168  for (size_t i=0;i<obs->size();i++)
169  {
170  const new_kf_observation_t &o = (*obs)[i];
171 
172  // If it's a new Landmark (observed for the first time, already not added to the data structures), just skip
173  // since we won't need spanning trees for it.
174  if (o.obs.feat_id>=m_parent->all_lms.size() || m_parent->all_lms[ o.obs.feat_id ].rfp==NULL)
175  continue;
176 
177  const TKeyFrameID base_id = m_parent->all_lms[ o.obs.feat_id ].rfp->id_frame_base;
178 
179  // make sure a spanning tree exists between "new_node_id" -> "base_id":
180  pending_checks.insert( TPairKeyFrameID( new_node_id, base_id ) );
181  }
182 
183  std::set<TPairKeyFrameID> done_checks;
184  while (!pending_checks.empty())
185  {
186  // Get first one:
187  const TPairKeyFrameID ft = *pending_checks.begin(); // copy, don't make a ref since we're deleting the element in the container!
188  pending_checks.erase(pending_checks.begin());
189 
190  if (done_checks.find(ft)!=done_checks.end())
191  continue; // We already done this one.
192 
193  // Create path:
194  std::map<TKeyFrameID,TSpanTreeEntry> & span_trees_from = sym.next_edge[ft.first];
195 
196  if ( span_trees_from.find(ft.second)==span_trees_from.end() )
197  { // It doesn't exist: create it.
198 
199  // We need the starting edge from "ft.first" in the direction towards "ft.second",
200  // and in the way mark as pending all the edges "intermediary node" -> "ft.second".
201  vector<TKeyFrameID> found_path;
202 
203  bool found = m_parent->find_path_bfs(
204  ft.first, // from
205  ft.second, // target node
206  &found_path);
207 
208  ASSERT_(found && !found_path.empty())
209 
210  // save direction:
211  TSpanTreeEntry & ste = span_trees_from[ft.second];
212  ste.distance = found_path.size();
213  ste.next = *found_path.rbegin(); // the last element
214 
215  // and append the rest of KFs as pending:
216  for (size_t i=0;i<found_path.size();i++)
217  if (found_path[i]!=ft.second)
218  pending_checks.insert( TPairKeyFrameID( found_path[i] , ft.second ) );
219 
220  // Remember to update the node's "all_edges" field:
221  kfs_with_modified_next_edge.insert( ft );
222  }
223 
224  // Mark as done:
225  done_checks.insert(ft);
226  }
227 
228  } // end if "check_all_obs_are_connected"
229 
230 
231 #if defined(SYM_ST_SUPER_VERBOSE_SAVE_ALL_SPANNING_TREES)
232  {
233  static int i=0;
234  const std::string sFil = mrpt::format("debug_spantree_%05i.txt",i);
235  const std::string sFilDot = mrpt::format("debug_spantree_%05i.dot",i);
236  const std::string sFilPng = mrpt::format("debug_spantree_%05i.png",i);
237  this->dump_as_text_to_file(sFil);
238  this->save_as_dot_file(sFilDot);
239  ::system(mrpt::format("dot %s -o %s -Tpng",sFilDot.c_str(), sFilPng.c_str() ).c_str());
240  i++;
241  }
242 #endif
243 
244  // Update "all_edges" --------------------------------------------
245  // Only for those who were really modified.
246  for (std::set<TPairKeyFrameID>::const_iterator it=kfs_with_modified_next_edge.begin();it!=kfs_with_modified_next_edge.end();++it)
247  {
248  const TKeyFrameID kf_id = it->first;
249  const std::map<TKeyFrameID,TSpanTreeEntry> & Ds = sym.next_edge[ kf_id ]; // O(1) in map_as_vector
250 
252  ASSERT_(it2!=Ds.end())
253 
254 
255  const TKeyFrameID dst_kf_id = it2->first;
256 
257  const TKeyFrameID from = std::max(dst_kf_id, kf_id);
258  const TKeyFrameID to = std::min(dst_kf_id, kf_id);
259 
260  // find_path_bfs
261  typename kf2kf_pose_traits<KF2KF_POSE_TYPE>::k2k_edge_vector_t & path = sym.all_edges[from][to]; // O(1) in map_as_vector
262  path.clear();
263  bool path_found = m_parent->find_path_bfs(from,to, NULL, &path);
264  ASSERT_(path_found)
265  } // end for each "kfs_with_modified_next_edge"
266 
267 
268 #if defined(SYM_ST_EXTRA_SECURITY_CHECKS)
269  {
270  // Security check: All spanning trees must have a max. depth of "max_depth"
271  // 1st step: define nodes & their depths:
272  for (next_edge_maps_t::const_iterator it1=sym.next_edge.begin();it1!=sym.next_edge.end();++it1)
273  for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=it1->second.begin();it!=it1->second.end();++it)
274  if (it->second.distance>max_depth)
275  {
276  std::stringstream s;
277  s << "CONSISTENCY ERROR: Spanning tree of kf #" << it1->first << " has kf #" << it->first
278  << " at depth=" << it->second.distance << " > Max=" << max_depth << endl;
279  s << "After updating symbolic spanning trees for new kf #" << new_node_id << " with new edges: ";
280  for (size_t i=0;i<new_edges.size();i++) s << new_edges[i].first << "->" << new_edges[i].second << ", ";
281  s << endl;
282  THROW_EXCEPTION(s.str())
283  }
284  }
285 #endif
286 }
287 
288 template <class k2k_edge_t>
289 struct TBFSEntry
290 {
291  TBFSEntry() : prev_edge(NULL),dist( std::numeric_limits<topo_dist_t>::max() )
292  {}
293 
295  k2k_edge_t *prev_edge;
297 };
298 
299 // Aux. function for "check_all_obs_are_connected":
300 // Breadth-first search (BFS) for "trg_node"
301 // Return: true: found
302 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
304  const TKeyFrameID cur_node,
305  const TKeyFrameID trg_node,
306  std::vector<TKeyFrameID> * out_path_IDs,
307  typename kf2kf_pose_traits<KF2KF_POSE_TYPE>::k2k_edge_vector_t * out_path_edges ) const
308 {
309  if (out_path_IDs) out_path_IDs->clear();
310  if (out_path_edges) out_path_edges->clear();
311  if (cur_node==trg_node) return true; // No need to do any search...
312 
313  std::set<TKeyFrameID> visited;
314  std::queue<TKeyFrameID> pending;
315  std::map<TKeyFrameID,TBFSEntry<k2k_edge_t> > preceding;
316 
317  // Insert:
318  pending.push(cur_node);
319  visited.insert(cur_node);
320  preceding[cur_node].dist = 0;
321 
322  while (!pending.empty())
323  {
324  const TKeyFrameID next_kf = pending.front();
325  pending.pop();
326 
327  TBFSEntry<k2k_edge_t> & bfs_data_next = preceding[next_kf];
328  const topo_dist_t cur_dist = bfs_data_next.dist;
329 
330  if (next_kf==trg_node)
331  {
332  // Path found: go thru the path in inverse order:
333  topo_dist_t dist = bfs_data_next.dist;
334  if (out_path_IDs) out_path_IDs->resize(dist);
335  if (out_path_edges) out_path_edges->resize(dist);
336  TKeyFrameID path_node = trg_node;
337  while (path_node != cur_node)
338  {
339  ASSERT_(dist>=0)
340  if (out_path_IDs) (*out_path_IDs)[--dist] = path_node;
341 
342  typename std::map<TKeyFrameID,TBFSEntry<k2k_edge_t> >::const_iterator it_prec = preceding.find(path_node);
343  ASSERT_(it_prec != preceding.end())
344  path_node = it_prec->second.prev;
345 
346  if (out_path_edges) (*out_path_edges)[--dist] = it_prec->second.prev_edge;
347  }
348  return true; // End of search
349  }
350 
351  // Get all connections of this node:
352  ASSERTDEB_(next_kf < keyframes.size())
353  const keyframe_info & kfi = keyframes[next_kf];
354 
355  for (size_t i=0;i<kfi.adjacent_k2k_edges.size();i++)
356  {
357  const k2k_edge_t* ed = kfi.adjacent_k2k_edges[i];
358  const TKeyFrameID new_kf = getTheOtherFromPair2(next_kf, *ed);
359  if (!visited.count(new_kf))
360  {
361  pending.push(new_kf);
362  visited.insert(new_kf);
363 
364  TBFSEntry<k2k_edge_t> & p = preceding[new_kf];
365 
366  if (p.dist>cur_dist+1)
367  {
368  p.dist = cur_dist+1;
369  p.prev = next_kf;
370  p.prev_edge = const_cast<k2k_edge_t*>(ed);
371  }
372  }
373  }
374  }
375  return false; // No path found.
376 }
377 
378 } } // end NS
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
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
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()
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.
#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
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
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.8 for MRPT 1.2.2 SVN:Unversioned directory at Tue Oct 14 02:14:08 UTC 2014