Main MRPT website > C++ reference
MRPT logo
spantree_misc.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 #include <iostream>
13 #include <fstream>
14 #include <sstream> // stringstream
15 
16 namespace mrpt { namespace srba {
17 
18 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
20 {
21  num.clear();
24 }
25 
26 
27 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
29 {
30  using mrpt::format;
31 
32  s.clear();
33 
34  s +=
35  " From | Shortest path to:=>Next node to move to [Distance] \n"
36  "--------+-----------------------------------------------------------------\n";
37  for (typename next_edge_maps_t::const_iterator it1=sym.next_edge.begin();it1!=sym.next_edge.end();++it1)
38  {
39  s += format(" %6u |",static_cast<unsigned int>(it1->first) );
40 
41  for (std::map<TKeyFrameID,TSpanTreeEntry>::const_iterator it2=it1->second.begin();it2!=it1->second.end();++it2)
42  s += format(" %5u:=>%5u [%u] |",static_cast<unsigned int>(it2->first), static_cast<unsigned int>(it2->second.next), static_cast<unsigned int>(it2->second.distance));
43 
44  s +=
45  "\n"
46  "--------+-----------------------------------------------------------------\n";
47  }
48 
49  s +=
50  "\n\n"
51  " From | To | Shortest path sequence \n"
52  "--------+--------+--------------------------------------------------------\n";
53  for (typename all_edges_maps_t::const_iterator it1=sym.all_edges.begin();it1!=sym.all_edges.end();++it1)
54  {
55  for (typename std::map<TKeyFrameID, k2k_edge_vector_t >::const_iterator it2=it1->second.begin();it2!=it1->second.end();++it2)
56  {
57  s += format(" %6u | %6u |",static_cast<unsigned int>(it1->first),static_cast<unsigned int>(it2->first) );
58 
59  const k2k_edge_vector_t & edges = it2->second;
60  for (typename k2k_edge_vector_t::const_iterator it3=edges.begin();it3!=edges.end();++it3)
61  s += format(" [%4u => %4u] ",static_cast<unsigned int>((*it3)->from),static_cast<unsigned int>((*it3)->to) );
62 
63  s+=
64  "\n"
65  "--------+--------+--------------------------------------------------------\n";
66  }
67  }
68 }
69 
70 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
72 {
73  std::ofstream f;
74  f.open(sFileName.c_str());
75  if (!f.is_open()) return false;
76 
77  std::string s;
78  this->dump_as_text(s);
79 
80  return !(f << s).fail();
81 }
82 
83 namespace internal
84 {
85  template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
87  std::set< std::pair<std::string,std::string> > & all_edges,
88  const std::string &prefix,
89  const TKeyFrameID came_from,
90  const TKeyFrameID root,
91  const std::map<TKeyFrameID,TSpanTreeEntry> &root_entries,
93  std::set<TKeyFrameID> &visited,
94  const std::map<TKeyFrameID,TSpanTreeEntry> &top_root_entries)
95  {
96  visited.insert(root);
97 
98  // All nodes at depth=1
99  for (std::map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=root_entries.begin();it!=root_entries.end();++it)
100  {
101  if (it->second.distance==1 && top_root_entries.find(it->first)!=top_root_entries.end())
102  {
103  const TKeyFrameID child = it->first;
104  //s << prefix << root << " -> " << prefix << child << ";\n";
105  const std::string s1 = prefix + mrpt::format("%06u",static_cast<unsigned int>( std::max(root,child) ));
106  const std::string s2 = prefix + mrpt::format("%06u",static_cast<unsigned int>( std::min(root,child) ));
107  all_edges.insert( make_pair(s1,s2) );
108 
109  if (!visited.count(it->first))
110  {
112  ASSERT_(it_ce != all.end())
113  internal::recursive_print_st_dot(all_edges,prefix,root,child,it_ce->second,all,visited,top_root_entries);
114  }
115  }
116  }
117  }
118 
119 } // end NS "internal"
120 
121 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
122 bool TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::save_as_dot_file(const std::string &sFileName, const std::vector<TKeyFrameID> &kf_roots_to_save ) const
123 {
124  using mrpt::format;
125  using namespace std;
126 
127  ofstream f;
128  f.open(sFileName.c_str());
129  if (!f.is_open()) return false;
130 
131  vector<next_edge_maps_t::const_iterator> its_to_process;
132 
133  if (kf_roots_to_save.empty())
134  {
135  // All:
136  its_to_process.reserve(sym.next_edge.size());
137  for (next_edge_maps_t::const_iterator it1=sym.next_edge.begin();it1!=sym.next_edge.end();++it1)
138  its_to_process.push_back(it1);
139  }
140  else
141  {
142  for (size_t i=0;i<kf_roots_to_save.size();i++)
143  {
144  next_edge_maps_t::const_iterator it=sym.next_edge.find(kf_roots_to_save[i]);
145  if (it!=sym.next_edge.end()) // silently ignore queries for KFs without a tree
146  its_to_process.push_back(it);
147  }
148  }
149 
150  stringstream s;
151 
152  s << "graph G {\n";
153 
154  map<size_t, set<string> > kfs_by_depth;
155  map<string, size_t> depth_kf;
156 
157  // 1st step: define nodes & their depths:
158  for (size_t k=0;k<its_to_process.size();k++)
159  {
160  const next_edge_maps_t::const_iterator it1=its_to_process[k];
161 
162  const TKeyFrameID root = it1->first;
163  const string sR = format("%06u",static_cast<unsigned int>(root) );
164 
165  const string sNodeDefR = sR + mrpt::format("%06u [label=%u]",static_cast<unsigned int>(root),static_cast<unsigned int>(root));
166  kfs_by_depth[0].insert( sNodeDefR );
167  depth_kf[mrpt::format("%06u%06u",static_cast<unsigned int>(root),static_cast<unsigned int>(root))] = 0;
168 
169  // All nodes at depth=1
170  for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=it1->second.begin();it!=it1->second.end();++it)
171  {
172  const string sNodeDef = sR + mrpt::format("%06u [label=%u]",static_cast<unsigned int>(it->first),static_cast<unsigned int>(it->first));
173  kfs_by_depth[it->second.distance].insert( sNodeDef );
174  depth_kf[mrpt::format("%06u%06u",static_cast<unsigned int>(root),static_cast<unsigned int>(it->first))] = it->second.distance;
175  }
176  }
177 
178  for (map<size_t, set<string> >::const_iterator it=kfs_by_depth.begin();it!=kfs_by_depth.end();++it)
179  {
180  //const size_t depth = it->first;
181  const set<string> & sNodes = it->second;
182 
183  s <<
184  "subgraph {\n"
185  " rank = same;\n";
186  for (set<string>::const_iterator itS=sNodes.begin();itS!=sNodes.end();++itS)
187  s << *itS << "\n";
188  s <<"};\n";
189  }
190 
191  // 2nd step: generate list of all edges in all trees:
192  set< pair<string,string> > all_edges;
193 
194  for (size_t k=0;k<its_to_process.size();k++)
195  {
196  const next_edge_maps_t::const_iterator it1=its_to_process[k];
197 
198  const TKeyFrameID root = it1->first;
199 
200  // All nodes at all depths:
201  for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=it1->second.begin();it!=it1->second.end();++it)
202  {
203  const TKeyFrameID other = it->first;
204 
205  const TKeyFrameID id1 = std::max(root,other);
206  const TKeyFrameID id2 = std::min(root,other);
207 
208  // Get all edges in the shortest path between them:
209  // (we only store <max,min> since this table is symmetric)
210  typename all_edges_maps_t::const_iterator it_eds_id1 = sym.all_edges.find(id1);
211  ASSERT_(it_eds_id1 != sym.all_edges.end())
212 
213  const std::map<TKeyFrameID, k2k_edge_vector_t> &eds_id1 = it_eds_id1->second;
214  typename std::map<TKeyFrameID, k2k_edge_vector_t>::const_iterator eds_it = eds_id1.find(id2);
215  ASSERT_(eds_it!=eds_id1.end())
216 
217  const k2k_edge_vector_t &eds = eds_it->second;
218 
219  for (size_t i=0;i<eds.size();i++)
220  {
221  const TKeyFrameID to = eds[i]->to;
222  const TKeyFrameID from = eds[i]->from;
223 
224  const string s1 = mrpt::format("%06u%06u",static_cast<unsigned int>(root),static_cast<unsigned int>( std::max(to,from) ));
225  const string s2 = mrpt::format("%06u%06u",static_cast<unsigned int>(root),static_cast<unsigned int>( std::min(to,from) ));
226 
227  all_edges.insert( make_pair(s1,s2) );
228  }
229  }
230  }
231 
232 
233  // And now only draw those at a different depth level:
234  for (set< pair<string,string> >::const_iterator it=all_edges.begin();it!=all_edges.end();++it)
235  s << it->first << " -- " << it->second << ";\n";
236 
237  // And now generate invisible edges between nodes across all depths ("ranks") so graphviz really put them in different physical heights:
238  for (map<size_t, set<string> >::const_iterator it=kfs_by_depth.begin();it!=kfs_by_depth.end();++it)
239  {
240  const set<string> & sNodes = it->second;
241  if (sNodes.empty()) continue; // But shouldn't occur!
242 
243  if (it!=kfs_by_depth.begin())
244  s << " -- ";
245 
246  s << it->second.begin()->substr(0,12) << " ";
247  }
248  if (!kfs_by_depth.empty()) s << " [style=invis];\n";
249 
250  s << "}\n";
251 
252  return !(f << s.str()).fail();
253 }
254 
255 
256 /** Returns min/max and mean/std stats on the number of nodes found on all the spanning trees. Runs in O(N), N=number of keyframes. */
257 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
259  size_t &num_nodes_min,
260  size_t &num_nodes_max,
261  double &num_nodes_mean,
262  double &num_nodes_std) const
263 {
264  num_nodes_min = 0;
265  num_nodes_max = 0;
266  num_nodes_mean = 0;
267  num_nodes_std = 0;
268 
269  std::vector<size_t> num_nodes;
270  num_nodes.reserve(sym.next_edge.size());
271 
272  for (next_edge_maps_t::const_iterator it1=sym.next_edge.begin();it1!=sym.next_edge.end();++it1)
273  num_nodes.push_back( it1->second.size() );
274 
275  mrpt::math::meanAndStd(num_nodes,num_nodes_mean,num_nodes_std);
276  mrpt::math::minimum_maximum(num_nodes, num_nodes_min, num_nodes_max);
277 }
278 
279 
280 } } // 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
kf2kf_pose_traits< KF2KF_POSE_TYPE >::k2k_edge_vector_t k2k_edge_vector_t
Definition: srba_types.h:478
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
iterator find(const size_t i)
Constant-time find, returning an iterator to the pair or to end() if not found (that is...
STL namespace.
const Scalar * const_iterator
Definition: eigen_plugins.h:24
void clear()
Clear the contents of this container.
Definition: map_as_vector.h:93
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 recursive_print_st_dot(std::set< std::pair< std::string, std::string > > &all_edges, const std::string &prefix, const TKeyFrameID came_from, const TKeyFrameID root, const std::map< TKeyFrameID, TSpanTreeEntry > &root_entries, const typename TRBA_Problem_state< KF2KF_POSE_TYPE, LM_TYPE, OBS_TYPE, RBA_OPTIONS >::TSpanningTree::next_edge_maps_t &all, std::set< TKeyFrameID > &visited, const std::map< TKeyFrameID, TSpanTreeEntry > &top_root_entries)
Definition: spantree_misc.h:86
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
void minimum_maximum(const std::vector< T > &V, T &curMin, T &curMax)
Return the maximum and minimum values of a std::vector.
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
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
void get_stats(size_t &num_nodes_min, size_t &num_nodes_max, double &num_nodes_mean, double &num_nodes_std) const
Returns min/max and mean/std stats on the number of nodes found on all the spanning trees...
void meanAndStd(const VECTORLIKE &v, double &out_mean, double &out_std, bool unbiased=true)
Computes the standard deviation of a vector.
#define ASSERT_(f)
void clear()
Empty all sym & num data.
Definition: spantree_misc.h:19
kf2kf_pose_traits< KF2KF_POSE_TYPE >::TRelativePosesForEachTarget num
"Numeric" spanning tree: the SE(3) pose of each node wrt to any other: num[SOURCE] |–> map[TARGET] =...
Definition: srba_types.h:550
void dump_as_text(std::string &s) const
Useful for debugging.
Definition: spantree_misc.h:28
bool dump_as_text_to_file(const std::string &sFileName) const
Useful for debugging.
Definition: spantree_misc.h:71
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