SRBA: Sparser Relative Bundle Adjustment
|
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