SRBA: Sparser Relative Bundle Adjustment
srba/impl/spantree_misc.h
00001 /* +---------------------------------------------------------------------------+
00002    |                     Mobile Robot Programming Toolkit (MRPT)               |
00003    |                          http://www.mrpt.org/                             |
00004    |                                                                           |
00005    | Copyright (c) 2005-2015, Individual contributors, see AUTHORS file        |
00006    | See: http://www.mrpt.org/Authors - All rights reserved.                   |
00007    | Released under BSD License. See details in http://www.mrpt.org/License    |
00008    +---------------------------------------------------------------------------+ */
00009 
00010 #pragma once
00011 
00012 #include <iostream>
00013 #include <fstream>
00014 #include <sstream>  // stringstream
00015 
00016 namespace srba {
00017 
00018 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
00019 void TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::clear()
00020 {
00021     num.clear();
00022     sym.next_edge.clear();
00023     sym.all_edges.clear();
00024 }
00025 
00026 
00027 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
00028 void TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::dump_as_text(std::string &s)  const
00029 {
00030     using mrpt::format;
00031 
00032     s.clear();
00033 
00034     s +=
00035     "  From  | Shortest path to:=>Next node to move to [Distance]              \n"
00036     "--------+-----------------------------------------------------------------\n";
00037     for (typename next_edge_maps_t::const_iterator it1=sym.next_edge.begin();it1!=sym.next_edge.end();++it1)
00038     {
00039         s += format(" %6u |",static_cast<unsigned int>(it1->first) );
00040 
00041         for (std::map<TKeyFrameID,TSpanTreeEntry>::const_iterator it2=it1->second.begin();it2!=it1->second.end();++it2)
00042             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));
00043 
00044         s +=
00045         "\n"
00046         "--------+-----------------------------------------------------------------\n";
00047     }
00048 
00049     s +=
00050     "\n\n"
00051     "  From  |   To   | Shortest path sequence                                 \n"
00052     "--------+--------+--------------------------------------------------------\n";
00053     for (typename all_edges_maps_t::const_iterator it1=sym.all_edges.begin();it1!=sym.all_edges.end();++it1)
00054     {
00055         for (typename std::map<TKeyFrameID, k2k_edge_vector_t >::const_iterator it2=it1->second.begin();it2!=it1->second.end();++it2)
00056         {
00057             s += format(" %6u | %6u |",static_cast<unsigned int>(it1->first),static_cast<unsigned int>(it2->first) );
00058 
00059             const k2k_edge_vector_t & edges = it2->second;
00060             for (typename k2k_edge_vector_t::const_iterator it3=edges.begin();it3!=edges.end();++it3)
00061                 s += format(" [%4u => %4u] ",static_cast<unsigned int>((*it3)->from),static_cast<unsigned int>((*it3)->to) );
00062 
00063             s+=
00064             "\n"
00065             "--------+--------+--------------------------------------------------------\n";
00066         }
00067     }
00068 }
00069 
00070 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
00071 bool TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::dump_as_text_to_file(const std::string &sFileName) const
00072 {
00073     std::ofstream f;
00074     f.open(sFileName.c_str());
00075     if (!f.is_open()) return false;
00076 
00077     std::string s;
00078     this->dump_as_text(s);
00079 
00080     return !(f << s).fail();
00081 }
00082 
00083 namespace internal
00084 {
00085     template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
00086     void recursive_print_st_dot(
00087         std::set< std::pair<std::string,std::string> > & all_edges,
00088         const std::string &prefix,
00089         const TKeyFrameID came_from,
00090         const TKeyFrameID root,
00091         const std::map<TKeyFrameID,TSpanTreeEntry> &root_entries,
00092         const typename TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::next_edge_maps_t &all,
00093         std::set<TKeyFrameID> &visited,
00094         const std::map<TKeyFrameID,TSpanTreeEntry> &top_root_entries)
00095     {
00096         visited.insert(root);
00097 
00098         // All nodes at depth=1
00099         for (std::map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=root_entries.begin();it!=root_entries.end();++it)
00100         {
00101             if (it->second.distance==1 && top_root_entries.find(it->first)!=top_root_entries.end())
00102             {
00103                 const TKeyFrameID child = it->first;
00104                 //s << prefix << root << " -> " << prefix << child << ";\n";
00105                 const std::string s1 = prefix + mrpt::format("%06u",static_cast<unsigned int>( std::max(root,child) ));
00106                 const std::string s2 = prefix + mrpt::format("%06u",static_cast<unsigned int>( std::min(root,child) ));
00107                 all_edges.insert( make_pair(s1,s2) );
00108 
00109                 if (!visited.count(it->first))
00110                 {
00111                     typename TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::next_edge_maps_t::const_iterator it_ce = all.find(child);
00112                     ASSERT_(it_ce != all.end())
00113                     internal::recursive_print_st_dot(all_edges,prefix,root,child,it_ce->second,all,visited,top_root_entries);
00114                 }
00115             }
00116         }
00117     }
00118 
00119 } // end NS "internal"
00120 
00121 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
00122 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
00123 {
00124     using mrpt::format;
00125     using namespace std;
00126 
00127     ofstream f;
00128     f.open(sFileName.c_str());
00129     if (!f.is_open()) return false;
00130 
00131     vector<next_edge_maps_t::const_iterator> its_to_process;
00132 
00133     if (kf_roots_to_save.empty())
00134     {
00135         // All:
00136         its_to_process.reserve(sym.next_edge.size());
00137         for (next_edge_maps_t::const_iterator it1=sym.next_edge.begin();it1!=sym.next_edge.end();++it1)
00138             its_to_process.push_back(it1);
00139     }
00140     else
00141     {
00142         for (size_t i=0;i<kf_roots_to_save.size();i++)
00143         {
00144             next_edge_maps_t::const_iterator it=sym.next_edge.find(kf_roots_to_save[i]);
00145             if (it!=sym.next_edge.end())  // silently ignore queries for KFs without a tree
00146                 its_to_process.push_back(it);
00147         }
00148     }
00149 
00150     stringstream s;
00151 
00152     s << "graph G {\n";
00153 
00154     map<size_t, set<string> >  kfs_by_depth;
00155     map<string, size_t>   depth_kf;
00156 
00157     // 1st step: define nodes & their depths:
00158     for (size_t k=0;k<its_to_process.size();k++)
00159     {
00160         const next_edge_maps_t::const_iterator it1=its_to_process[k];
00161 
00162         const TKeyFrameID root = it1->first;
00163         const string sR = format("%06u",static_cast<unsigned int>(root) );
00164 
00165         const string sNodeDefR = sR + mrpt::format("%06u [label=%u]",static_cast<unsigned int>(root),static_cast<unsigned int>(root));
00166         kfs_by_depth[0].insert( sNodeDefR );
00167         depth_kf[mrpt::format("%06u%06u",static_cast<unsigned int>(root),static_cast<unsigned int>(root))] = 0;
00168 
00169         // All nodes at depth=1
00170         for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=it1->second.begin();it!=it1->second.end();++it)
00171         {
00172             const string sNodeDef = sR + mrpt::format("%06u [label=%u]",static_cast<unsigned int>(it->first),static_cast<unsigned int>(it->first));
00173             kfs_by_depth[it->second.distance].insert( sNodeDef );
00174             depth_kf[mrpt::format("%06u%06u",static_cast<unsigned int>(root),static_cast<unsigned int>(it->first))] = it->second.distance;
00175         }
00176     }
00177 
00178     for (map<size_t, set<string> >::const_iterator it=kfs_by_depth.begin();it!=kfs_by_depth.end();++it)
00179     {
00180         //const size_t depth = it->first;
00181         const set<string> & sNodes = it->second;
00182 
00183         s <<
00184         "subgraph {\n"
00185         "  rank = same;\n";
00186         for (set<string>::const_iterator itS=sNodes.begin();itS!=sNodes.end();++itS)
00187             s << *itS << "\n";
00188         s <<"};\n";
00189     }
00190 
00191     // 2nd step: generate list of all edges in all trees:
00192     set< pair<string,string> > all_edges;
00193 
00194     for (size_t k=0;k<its_to_process.size();k++)
00195     {
00196         const next_edge_maps_t::const_iterator it1=its_to_process[k];
00197 
00198         const TKeyFrameID root = it1->first;
00199 
00200         // All nodes at all depths:
00201         for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=it1->second.begin();it!=it1->second.end();++it)
00202         {
00203             const TKeyFrameID other = it->first;
00204 
00205             const TKeyFrameID id1 = std::max(root,other);
00206             const TKeyFrameID id2 = std::min(root,other);
00207 
00208             // Get all edges in the shortest path between them:
00209             // (we only store <max,min> since this table is symmetric)
00210             typename all_edges_maps_t::const_iterator it_eds_id1 = sym.all_edges.find(id1);
00211             ASSERT_(it_eds_id1 != sym.all_edges.end())
00212 
00213             const std::map<TKeyFrameID, k2k_edge_vector_t> &eds_id1 = it_eds_id1->second;
00214             typename std::map<TKeyFrameID, k2k_edge_vector_t>::const_iterator eds_it = eds_id1.find(id2);
00215             ASSERT_(eds_it!=eds_id1.end())
00216 
00217             const k2k_edge_vector_t &eds = eds_it->second;
00218 
00219             for (size_t i=0;i<eds.size();i++)
00220             {
00221                 const TKeyFrameID to   = eds[i]->to;
00222                 const TKeyFrameID from = eds[i]->from;
00223 
00224                 const string s1 = mrpt::format("%06u%06u",static_cast<unsigned int>(root),static_cast<unsigned int>( std::max(to,from) ));
00225                 const string s2 = mrpt::format("%06u%06u",static_cast<unsigned int>(root),static_cast<unsigned int>( std::min(to,from) ));
00226 
00227                 all_edges.insert( make_pair(s1,s2) );
00228             }
00229         }
00230     }
00231 
00232 
00233     // And now only draw those at a different depth level:
00234     for (set< pair<string,string> >::const_iterator it=all_edges.begin();it!=all_edges.end();++it)
00235             s << it->first << " -- " << it->second << ";\n";
00236 
00237     // And now generate invisible edges between nodes across all depths ("ranks") so graphviz really put them in different physical heights:
00238     for (map<size_t, set<string> >::const_iterator it=kfs_by_depth.begin();it!=kfs_by_depth.end();++it)
00239     {
00240         const set<string> & sNodes = it->second;
00241         if (sNodes.empty()) continue; // But shouldn't occur!
00242 
00243         if (it!=kfs_by_depth.begin())
00244           s << " -- ";
00245 
00246         s << it->second.begin()->substr(0,12) << " ";
00247     }
00248     if (!kfs_by_depth.empty()) s << " [style=invis];\n";
00249 
00250     s << "}\n";
00251 
00252     return !(f << s.str()).fail();
00253 }
00254 
00255 
00257 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
00258 void TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::get_stats(
00259     size_t &num_nodes_min,
00260     size_t &num_nodes_max,
00261     double &num_nodes_mean,
00262     double &num_nodes_std) const
00263 {
00264     num_nodes_min = 0;
00265     num_nodes_max  = 0;
00266     num_nodes_mean  = 0;
00267     num_nodes_std  = 0;
00268 
00269     std::vector<size_t> num_nodes;
00270     num_nodes.reserve(sym.next_edge.size());
00271 
00272     for (next_edge_maps_t::const_iterator it1=sym.next_edge.begin();it1!=sym.next_edge.end();++it1)
00273         num_nodes.push_back( it1->second.size() );
00274 
00275     mrpt::math::meanAndStd(num_nodes,num_nodes_mean,num_nodes_std);
00276     mrpt::math::minimum_maximum(num_nodes, num_nodes_min, num_nodes_max);
00277 }
00278 
00279 
00280 } // end NS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends