SRBA: Sparser Relative Bundle Adjustment
srba/impl/spantree_update_symbolic.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 namespace srba {
00013 
00014 
00015 #define SYM_ST_SUPER_VERBOSE 0
00016 
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::update_symbolic_new_node(
00020     const TKeyFrameID                    new_node_id,
00021     const TPairKeyFrameID & new_edge,
00022     const topo_dist_t                    max_depth
00023     )
00024 {
00025     using namespace std;
00026     ASSERT_(max_depth>=1)
00027 
00028     // Maintain a list of those nodes whose list of shortest spanning trees ("next_edge") has been modified, so we
00029     // can rebuild their "all_edges" lists.
00030     std::set<TPairKeyFrameID> kfs_with_modified_next_edge;
00031 
00032     // Generic algorithm for 1 or more new edges at once from the new_kf_id to the rest of the graph:
00033     // -----------------------------------------------------------------------------------------------
00034     // The first edge was already introduced in the STs above. Go on with the rest:
00035     // (Notation is according to the ICRA2013 paper, see explanatory graphs or understanding this is a hell!! ;-)
00036     {
00037         //const TKeyFrameID ik = getTheOtherFromPair(new_node_id, new_edges[nE] );
00038         const TKeyFrameID ik = getTheOtherFromPair(new_node_id, new_edge );
00039 
00040         // Build set tk = all nodes within distance <=(max_depth-1) from "ik"
00041         const map<TKeyFrameID,TSpanTreeEntry> & st_ik = sym.next_edge[ik];  // O(1)
00042         vector<pair<TKeyFrameID,topo_dist_t> > tk;
00043         for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=st_ik.begin();it!=st_ik.end();++it)
00044             if (it->second.distance<max_depth)
00045                 tk.push_back( make_pair(it->first,it->second.distance) );
00046         tk.push_back( make_pair(ik,0) ); // The set includes the root itself, which is not in the STs structures.
00047 
00048         // Build set STn = all nodes within distance <=max_depth from "new_node_id"
00049         // This will also CREATE the empty ST for "new_node_id" upon first call to [], in amortized O(1)
00050         const map<TKeyFrameID,TSpanTreeEntry> & st_n = sym.next_edge[new_node_id];  // access O(1)
00051         vector<pair<TKeyFrameID,const TSpanTreeEntry*> > STn;
00052         for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=st_n.begin();it!=st_n.end();++it)
00053             STn.push_back( make_pair(it->first,&it->second) );
00054         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.
00055 
00056         // for each r \in ST_W(n)
00057         for (size_t r_idx=0;r_idx<STn.size();r_idx++)
00058         {
00059             const TKeyFrameID      r        = STn[r_idx].first;
00060             const TSpanTreeEntry * ste_n2r  = STn[r_idx].second;
00061             const topo_dist_t      dist_r2n = ste_n2r ? ste_n2r->distance : 0;
00062 
00063             map<TKeyFrameID,TSpanTreeEntry> & st_r = sym.next_edge[r];  // O(1)
00064 
00065             TSpanTreeEntry * ste_r2n = NULL; // Will stay NULL for r=new_node_id
00066             if (r!=new_node_id)
00067             {
00068                 map<TKeyFrameID,TSpanTreeEntry>::iterator it = st_r.find(new_node_id);
00069                 ASSERT_(it!=st_r.end())
00070                 ste_r2n = &it->second;
00071             }
00072 
00073             // for each s \in ST_{W-1}(i_k)
00074             for (size_t s_idx=0;s_idx<tk.size();s_idx++)
00075             {
00076                 const TKeyFrameID s         = tk[s_idx].first;
00077                 if (r==s) continue;
00078                 const topo_dist_t dist_s2ik = tk[s_idx].second;
00079 
00080                 map<TKeyFrameID,TSpanTreeEntry> & st_s = sym.next_edge[s];  // O(1)
00081 
00082                 TSpanTreeEntry *ste_s2ik=NULL;  // =NULL if s==ik
00083                 if (s!=ik)
00084                 {
00085                     map<TKeyFrameID,TSpanTreeEntry>::iterator it_ik_inSTs = st_s.find(ik);
00086                     ASSERTDEB_(it_ik_inSTs != st_s.end())
00087                     ste_s2ik = &it_ik_inSTs->second;
00088                 }
00089 
00090                 // new tentative distance s <--> ik
00091                 const topo_dist_t new_dist = dist_r2n + dist_s2ik + 1;
00092 
00093                 // Is s \in ST(r)?
00094                 map<TKeyFrameID,TSpanTreeEntry>::iterator it_s_inSTr = st_r.find(s);    // O(log N)
00095                 if (it_s_inSTr != st_r.end())
00096                 {   // Found:
00097                     // Is it shorter to go (r)->(n)--[dist=1]-->(ik)->(s) than (r)->(s) ? Then modify spanning tree
00098                     if (new_dist < it_s_inSTr->second.distance)
00099                     {
00100 #if SYM_ST_SUPER_VERBOSE
00101 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;
00102 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;
00103 #endif
00104                         // It's shorter: change spanning tree
00105                         //  ST[r][s]
00106                         it_s_inSTr->second.distance = new_dist;
00107                         it_s_inSTr->second.next     = ste_r2n ? ste_r2n->next : ik;  // Next node in the direction towards "new_node_id"
00108                         ASSERT_NOT_EQUAL_(r,it_s_inSTr->second.next) // no self-loops!
00109 
00110                         //  ST[s][r]
00111                         TSpanTreeEntry &ste_r_inSTs = st_s[r];
00112                         ste_r_inSTs.distance = new_dist;
00113                         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"
00114                         ASSERT_NOT_EQUAL_(s,ste_r_inSTs.next) // no self-loops!
00115 
00116                         // Mark nodes with their "next_node" modified:
00117                         kfs_with_modified_next_edge.insert( make_pair(s,r) );
00118                         kfs_with_modified_next_edge.insert( make_pair(r,s) );
00119                     }
00120                     // Otherwise, leave things stay.
00121                 }
00122                 else
00123                 {   // Not found:
00124                     if (new_dist<=max_depth)
00125                     {
00126 #if SYM_ST_SUPER_VERBOSE
00127 cout << "ST: New path ST["<<r<<"]["<<s<<"].N ="<<(ste_r2n ? ste_r2n->next : ik) << "[D:"<<dist_r2n + dist_s2ik + 1<<"]"<<endl;
00128 cout << "ST: New path ST["<<s<<"]["<<r<<"].N ="<<(ste_s2ik ? ste_s2ik->next : new_node_id) << "[D:"<<dist_r2n + dist_s2ik + 1<<"]"<<endl;
00129 #endif
00130 
00131                         // Then the node "s" wasn't reachable from "r" but now it is:
00132                         //  ST[r][s]
00133                         TSpanTreeEntry &ste_s_inSTr = st_r[s]; // O(log N)
00134 
00135                         ste_s_inSTr.distance = new_dist;
00136                         ste_s_inSTr.next     = ste_r2n ? ste_r2n->next : ik;  // Next node in the direction towards "new_node_id"
00137                         ASSERT_NOT_EQUAL_(r,ste_s_inSTr.next) // no self-loops!
00138 
00139                         //  ST[s][r]
00140                         TSpanTreeEntry &ste_r_inSTs = st_s[r]; // O(log N)
00141                         ste_r_inSTs.distance = new_dist;
00142                         ste_r_inSTs.next     = ste_s2ik ? ste_s2ik->next : new_node_id; // Next node in the direction towards "ik"
00143                         ASSERT_NOT_EQUAL_(s, ste_r_inSTs.next) // no self-loops!
00144 
00145                         // Mark nodes with their "next_node" modified:
00146                         kfs_with_modified_next_edge.insert(make_pair(r,s));
00147                         kfs_with_modified_next_edge.insert(make_pair(s,r));
00148                     }
00149                 }
00150 
00151             } // end for each s
00152         } // end for each r
00153 
00154     } // end for each new edge
00155 
00156 #if defined(SYM_ST_SUPER_VERBOSE_SAVE_ALL_SPANNING_TREES)
00157     {
00158         static int i=0;
00159         const std::string sFil    = mrpt::format("debug_spantree_%05i.txt",i);
00160         const std::string sFilDot = mrpt::format("debug_spantree_%05i.dot",i);
00161         const std::string sFilPng = mrpt::format("debug_spantree_%05i.png",i);
00162         this->dump_as_text_to_file(sFil);
00163         this->save_as_dot_file(sFilDot);
00164         ::system(mrpt::format("dot %s -o %s -Tpng",sFilDot.c_str(), sFilPng.c_str() ).c_str());
00165         i++;
00166     }
00167 #endif
00168 
00169     // Update "all_edges" --------------------------------------------
00170     // Only for those who were really modified.
00171     for (std::set<TPairKeyFrameID>::const_iterator it=kfs_with_modified_next_edge.begin();it!=kfs_with_modified_next_edge.end();++it)
00172     {
00173         const TKeyFrameID kf_id = it->first;
00174         const std::map<TKeyFrameID,TSpanTreeEntry> & Ds = sym.next_edge[ kf_id ];  // O(1) in map_as_vector
00175 
00176         std::map<TKeyFrameID,TSpanTreeEntry>::const_iterator it2=Ds.find(it->second);
00177         ASSERT_(it2!=Ds.end())
00178         
00179 
00180         const TKeyFrameID dst_kf_id = it2->first;
00181 
00182         const TKeyFrameID from = std::max(dst_kf_id, kf_id);
00183         const TKeyFrameID to   = std::min(dst_kf_id, kf_id);
00184 
00185         // find_path_bfs
00186         typename kf2kf_pose_traits<KF2KF_POSE_TYPE>::k2k_edge_vector_t & path = sym.all_edges[from][to];  // O(1) in map_as_vector
00187         path.clear();
00188         bool path_found = m_parent->find_path_bfs(from,to, NULL, &path);
00189         ASSERT_(path_found)
00190     } // end for each "kfs_with_modified_next_edge"
00191 
00192 
00193 #if defined(SYM_ST_EXTRA_SECURITY_CHECKS)
00194     {
00195         // Security check: All spanning trees must have a max. depth of "max_depth"
00196         // 1st step: define nodes & their depths:
00197         for (next_edge_maps_t::const_iterator it1=sym.next_edge.begin();it1!=sym.next_edge.end();++it1)
00198             for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=it1->second.begin();it!=it1->second.end();++it)
00199                 if (it->second.distance>max_depth)
00200                 {
00201                     std::stringstream s;
00202                     s << "CONSISTENCY ERROR: Spanning tree of kf #" << it1->first << " has kf #" << it->first
00203                     << " at depth=" << it->second.distance << " > Max=" << max_depth << endl;
00204                     s << "After updating symbolic spanning trees for new kf #" << new_node_id << " with new edges: ";
00205                     for (size_t i=0;i<new_edges.size();i++) s << new_edges[i].first << "->" << new_edges[i].second << ", ";
00206                     s << endl;
00207                     THROW_EXCEPTION(s.str())
00208                 }
00209     }
00210 #endif
00211 }
00212 
00213 template <class k2k_edge_t>
00214 struct TBFSEntry
00215 {
00216     TBFSEntry() : prev_edge(NULL),dist( std::numeric_limits<topo_dist_t>::max() )
00217     {}
00218 
00219     TKeyFrameID prev;
00220     k2k_edge_t *prev_edge;
00221     topo_dist_t dist;
00222 };
00223 
00224 //  Breadth-first search (BFS) for "trg_node"
00225 //  Return: true: found
00226 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS>
00227 bool TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::find_path_bfs(
00228     const TKeyFrameID           cur_node,
00229     const TKeyFrameID           trg_node,
00230     std::vector<TKeyFrameID>  * out_path_IDs,
00231     typename kf2kf_pose_traits<KF2KF_POSE_TYPE>::k2k_edge_vector_t * out_path_edges ) const
00232 {
00233     if (out_path_IDs) out_path_IDs->clear();
00234     if (out_path_edges) out_path_edges->clear();
00235     if (cur_node==trg_node) return true; // No need to do any search...
00236 
00237     std::set<TKeyFrameID>   visited;
00238     std::queue<TKeyFrameID> pending;
00239     std::map<TKeyFrameID,TBFSEntry<k2k_edge_t> >    preceding;
00240 
00241     // Insert:
00242     pending.push(cur_node);
00243     visited.insert(cur_node);
00244     preceding[cur_node].dist = 0;
00245 
00246     while (!pending.empty())
00247     {
00248         const TKeyFrameID next_kf = pending.front();
00249         pending.pop();
00250 
00251         TBFSEntry<k2k_edge_t> & bfs_data_next = preceding[next_kf];
00252         const topo_dist_t cur_dist = bfs_data_next.dist;
00253 
00254         if (next_kf==trg_node)
00255         {
00256             // Path found: go thru the path in inverse order:
00257             topo_dist_t  dist = bfs_data_next.dist;
00258             if (out_path_IDs) out_path_IDs->resize(dist);
00259             if (out_path_edges) out_path_edges->resize(dist);
00260             TKeyFrameID path_node = trg_node;
00261             while (path_node != cur_node)
00262             {
00263                 ASSERT_(dist>0)
00264                 if (out_path_IDs) (*out_path_IDs)[--dist] = path_node;
00265 
00266                 typename std::map<TKeyFrameID,TBFSEntry<k2k_edge_t> >::const_iterator it_prec = preceding.find(path_node);
00267                 ASSERT_(it_prec != preceding.end())
00268                 path_node = it_prec->second.prev;
00269 
00270                 if (out_path_edges) (*out_path_edges)[--dist] = it_prec->second.prev_edge;
00271             }
00272             return true; // End of search
00273         }
00274 
00275         // Get all connections of this node:
00276         ASSERTDEB_(next_kf < keyframes.size())
00277         const keyframe_info & kfi = keyframes[next_kf];
00278 
00279         for (size_t i=0;i<kfi.adjacent_k2k_edges.size();i++)
00280         {
00281             const k2k_edge_t* ed = kfi.adjacent_k2k_edges[i];
00282             const TKeyFrameID new_kf = getTheOtherFromPair2(next_kf, *ed);
00283             if (!visited.count(new_kf))
00284             {
00285                 pending.push(new_kf);
00286                 visited.insert(new_kf);
00287 
00288                 TBFSEntry<k2k_edge_t> & p = preceding[new_kf];
00289 
00290                 if (p.dist>cur_dist+1)
00291                 {
00292                     p.dist = cur_dist+1;
00293                     p.prev = next_kf;
00294                     p.prev_edge = const_cast<k2k_edge_t*>(ed);
00295                 }
00296             }
00297         }
00298     }
00299     return false; // No path found.
00300 }
00301 
00302 } // end NS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends