Jafar
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
algorithms.hpp
00001 #ifndef ALGORITHMS_HPP
00002 #define ALGORITHMS_HPP
00003 
00004 #include <boost/graph/depth_first_search.hpp>
00005 #include <boost/graph/undirected_dfs.hpp>
00006 #include <boost/graph/reverse_graph.hpp>
00007 #include <boost/graph/copy.hpp>
00008 #include <boost/graph/adjacency_list.hpp>
00009 
00010 #include <graphmap/transformation.hpp>
00011 #include <graphmap/graphmapException.hpp>
00012 
00013 #include <rtslam/quatTools.hpp>
00014 
00015 #include <iostream>
00016 #include <algorithm>
00017 
00018 namespace jafar{
00019 namespace graphmap {
00020 
00021 template <typename OutputIterator, typename OutputIteratorValueType>
00022 class path_to_back_edge_recorder : public boost::default_dfs_visitor
00023 {
00024 public:
00025   path_to_back_edge_recorder(OutputIterator out) :
00026     m_out(out), m_path()
00027   { }
00028 
00029   template <class Edge, class Graph>
00030   void tree_edge(Edge e, Graph&) { m_path.push_back(e); }
00031   template <class Vertex, class Graph>
00032   void finish_vertex(Vertex, Graph&){ if(!m_path.empty()) m_path.pop_back();  }
00033   template <class Edge, class Graph>
00034   void back_edge(Edge e, Graph&)
00035   {
00036     if(e == m_path.back()) return; // avoid going back through the same undirected edge
00037 
00038     m_path.push_back(e);
00039     *m_out++ = m_path;
00040     m_path.pop_back();
00041   }
00042 
00043 private:
00044   OutputIterator m_out;
00045   OutputIteratorValueType m_path;
00046 };
00047 
00048 //object generator function
00049 template <typename BackInsertionSequence>
00050 path_to_back_edge_recorder< std::back_insert_iterator<BackInsertionSequence>, typename BackInsertionSequence::value_type >
00051 make_path_to_back_edge_recorder(BackInsertionSequence& backinsertersequence) {
00052   return path_to_back_edge_recorder<std::back_insert_iterator<BackInsertionSequence>, typename BackInsertionSequence::value_type >(std::back_inserter(backinsertersequence));
00053 }
00054 
00055 template <typename OutputIterator, typename OutputIteratorValueType, typename Vertex>
00056 class path_to_target_recorder : public boost::default_dfs_visitor
00057 {
00058 public:
00059   path_to_target_recorder(OutputIterator out, Vertex target) :
00060     m_out(out), m_path(), m_target(target)
00061   { }
00062 
00063   template <class Edge, class Graph>
00064   void tree_edge(Edge e, Graph&) { m_path.push_back(e); }
00065   template <class Graph>
00066   void finish_vertex(Vertex, Graph&){ if(!m_path.empty()) m_path.pop_back();  }
00067   template <class Graph>
00068   void discover_vertex(Vertex u, Graph& g) {
00069     if(u == m_target){
00070       *m_out++ = m_path;
00071     }
00072   }
00073 private:
00074   OutputIterator m_out;
00075   OutputIteratorValueType m_path;
00076   Vertex m_source, m_target;
00077 };
00078 
00079 //object generator function
00080 template <typename BackInsertionSequence, typename Vertex>
00081 path_to_target_recorder< std::back_insert_iterator<BackInsertionSequence>, typename BackInsertionSequence::value_type, Vertex >
00082 make_path_to_target_recorder(BackInsertionSequence& backinsertersequence, Vertex target) {
00083   return path_to_target_recorder<std::back_insert_iterator<BackInsertionSequence>, typename BackInsertionSequence::value_type, Vertex >(std::back_inserter(backinsertersequence),target);
00084 }
00085 
00086 
00087 template<typename Loop,typename Graph>
00088 void tag_loop(Loop &loop, Graph &g)
00089 {
00090   typename Loop::iterator it = loop.begin();
00091   std::vector<unsigned int> common_ids, intersection; 
00092 
00093   common_ids = g[(*it)].loop_ids; it++;
00094 
00095   for( ; it != loop.end(); ++it)
00096   {
00097     std::set_intersection (g[(*it)].loop_ids.begin(),g[(*it)].loop_ids.end(),
00098                  common_ids.begin(),common_ids.end(),
00099                  std::back_inserter(intersection));
00100     if(intersection.empty())  // No common loop id: assign a new one and return
00101     {
00102       unsigned int new_id = g[boost::graph_bundle].loopIdFactory.getId();
00103       JFR_DEBUG("New loop! ID: " << new_id << std::endl);
00104       for(typename Loop::iterator it2  = loop.begin(); it2 != loop.end(); ++it2)
00105         g[(*it2)].loop_ids.push_back(new_id);
00106       return;
00107     }else
00108     {
00109       common_ids = intersection;
00110       intersection.clear();
00111     }
00112   }
00113 
00114   JFR_DEBUG_COND(common_ids.size() == 1,"Old loop... ID: " << common_ids.front() << std::endl);
00115   JFR_PRED_ERROR(common_ids.size() != 1, GraphmapException, GraphmapException::LOOP_WITH_MULTIPLE_IDS, "loop has " << common_ids.size() << " ids");
00116 }
00117 
00118 template <typename Path, typename Graph>
00119 void compute_loop_from_path(Path& path, Graph& g)
00120 {
00121   using namespace boost;
00122 
00123   typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
00124   typedef typename graph_traits<Graph>::edge_descriptor Edge;
00125 
00126   Edge back_edge = path.back();
00127   Vertex loop_head = target(back_edge,g);
00128 
00129   if(source(path.front(),g) != loop_head){
00130     typename Path::iterator it;
00131     for(it = path.begin(); it != path.end(); ++it)
00132       if(source(*it,g) == loop_head){
00133         path.erase(path.begin(),it); //Erase all edges that do not belong to the loop
00134         return;
00135       }
00136   }
00137 }
00138 
00142 template <typename Graph, typename Loops>
00143 void find_all_loops(
00144     typename boost::graph_traits<Graph>::vertex_descriptor entry,
00145     Graph& g,
00146     Loops& loops) // A container of sets of edges
00147 {
00148   using namespace boost;
00149 
00150   function_requires< BidirectionalGraphConcept<Graph> >();
00151   typedef typename graph_traits<Graph>::edge_descriptor Edge;
00152   typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
00153 
00154   //std::vector<default_color_type> color_map(num_vertices(g));
00155 
00157   // Find paths from the entry vertex to the back edges in the graph
00158   depth_first_search(g,visitor(make_path_to_back_edge_recorder(loops)));
00160   //undirected_dfs(g,visitor(make_path_to_back_edge_recorder(loops)));
00161 
00162   // Find all the vertices in each loop
00163   for(typename Loops::iterator it = loops.begin();
00164     it != loops.end(); ++it)
00165   {
00166     compute_loop_from_path(*it,g);
00167     tag_loop(*it,g);
00168   }
00169 
00171 
00172 }
00173 
00181 template <typename Graph, typename Loops>
00182 void find_loops_from_edge(
00183     typename boost::graph_traits<Graph>::edge_descriptor entry_edge,
00184     Graph& g,
00185     Loops& loops) // A container of sets of edges
00186 {
00187   using namespace boost;
00188 
00189   function_requires< BidirectionalGraphConcept<Graph> >();
00190   typedef typename graph_traits<Graph>::edge_descriptor Edge;
00191   typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
00192   typedef typename graph_traits<Graph>::edge_iterator EdgeIterator;
00193   typedef adjacency_list<listS, vecS, undirectedS> UndirectedGraph;
00194   typedef typename graph_traits<UndirectedGraph>::edge_descriptor UndirectedEdge;
00195   typedef typename graph_traits<UndirectedGraph>::vertex_descriptor UndirectedVertex;
00196   typedef typename std::list<UndirectedEdge> UndirectedEdgeList;
00197   typedef typename std::vector<UndirectedEdgeList> UndirectedLoops;
00198 
00199   UndirectedLoops und_loops;
00200   UndirectedGraph undirected_g;
00201   std::map<Edge,UndirectedEdge> direct_to_undirect_edge_map;
00202   std::map<UndirectedEdge,Edge> undirect_to_direct_edge_map;
00203 
00204   // copy the directed graph to a undirected one
00205   EdgeIterator ei, ei_end;
00206   UndirectedEdge und_e;
00207   for (tie(ei, ei_end) = edges(g); ei != ei_end; ++ei){
00208     tie(und_e,boost::tuples::ignore) = add_edge(source(*ei, g),target(*ei, g),undirected_g);
00209     direct_to_undirect_edge_map[*ei] = und_e;
00210     undirect_to_direct_edge_map[und_e] = *ei;
00211   }
00212 
00213   // record the source and target vertexes in the undirected graph
00214   UndirectedVertex source_v = source(direct_to_undirect_edge_map[entry_edge],undirected_g);
00215   UndirectedVertex target_v = target(direct_to_undirect_edge_map[entry_edge],undirected_g);
00216 
00217   // remove the entry edge from the undirected graph
00218   remove_edge(direct_to_undirect_edge_map[entry_edge],undirected_g);
00219 
00220   // search for a path from source to target vertexes
00221   std::vector < default_color_type > color_map(num_vertices(undirected_g));
00222   depth_first_visit(undirected_g, source_v,
00223             make_path_to_target_recorder(und_loops,target_v),
00224             make_iterator_property_map(color_map.begin(),
00225                          get(vertex_index, undirected_g), color_map[0]));
00226 
00227   // convert the loop from undirected to directed, adding the entry edge
00228   for(typename UndirectedLoops::iterator it = und_loops.begin();
00229     it != und_loops.end(); ++it)
00230   {
00231     typename Loops::value_type directed_loop;
00232     for(typename UndirectedEdgeList::iterator it2 = it->begin();
00233       it2 != it->end(); ++it2)
00234     {
00235       directed_loop.push_back(undirect_to_direct_edge_map[*it2]);
00236     }
00237     directed_loop.push_back(entry_edge);
00238     loops.push_back(directed_loop);
00239   }
00240 
00241   // Tag the loops
00242   for(typename Loops::iterator it = loops.begin(); it != loops.end(); ++it)
00243   {
00244     tag_loop(*it,g);
00245   }
00246 
00247 }
00248 
00249 template <typename TransformationPairVector>
00250 void optimize(TransformationPairVector &t_pair_vector, double threshold)
00251 {
00252   unsigned int loop_size = t_pair_vector.size();
00253 
00254   // Define the optimization vector size
00255   int t_size = t_pair_vector[0].first.size();
00256   int opt_vec_size = t_size * loop_size;
00257 
00258   jblas::vec x_u(opt_vec_size); // vector of original transformations
00259   jblas::sym_mat P_u(opt_vec_size,opt_vec_size); // matrix of original covariances OBS: need to be sym_mat to avoid ambiguity using prod_JPJt
00260   jblas::vec x_prev(opt_vec_size); // vector of optimazed transformations
00261   jblas::vec x_pos(opt_vec_size); // vector of optimazed transformations
00262 
00263   // Initialize x_u, P_u, x_i = x_0 and h_i = h_0
00264   for(unsigned int i=0; i < loop_size; ++i)
00265   {
00266     ublas::subrange(x_u,i*t_size,(i+1)*t_size) = t_pair_vector[i].first.x();
00267     ublas::subrange(P_u,i*t_size,(i+1)*t_size,i*t_size,(i+1)*t_size) = t_pair_vector[i].first.P();
00268     ublas::subrange(x_prev,i*t_size,(i+1)*t_size) = t_pair_vector[i].second.x();
00269   }
00270 
00271   bool converged = false;
00272 
00273   // Jacobian of h evaluated in x_i
00274   jblas::mat H_i(t_size,opt_vec_size);
00275 
00276   // Auxiliary variables to calculate x_i
00277   jblas::vec a(opt_vec_size);
00278   jblas::vec b(opt_vec_size);
00279   jblas::vec c(t_size);
00280   jblas::mat d(t_size,t_size);
00281   jblas::mat d_inv(t_size,t_size);
00282   jblas::mat e(opt_vec_size,t_size);
00283   jblas::mat f(opt_vec_size,t_size);
00284   jblas::vec g(opt_vec_size);
00285 
00286   jblas::vec h_i = jblas::zero_vec(t_size); // composition of transformations
00287   jblas::vec h_k(t_size); // incremental composition of transformations (used to calculate H_i)
00288   jblas::vec x_k(t_size); // transformation of one specific edge
00289 
00290   jblas::mat J_1(t_size,t_size), J_2(t_size,t_size); // Jacobians used to evaluate H_i
00291 
00292   // dummy variables used to be able to get the right jacobians in H_i evaluation
00293   jblas::mat dummy_J(t_size,t_size);
00294   jblas::vec dummy_C(t_size);
00295 
00296   // temporary variables used to evaluate H_i
00297   jblas::vec h_k_inv(t_size), h_k_inv_h_i(t_size), x_k_inv(t_size), h_k_x_k_inv(t_size);
00298 
00299   while(!converged){
00300     // evaluate h_i
00301     for(unsigned int i=0; i < loop_size; ++i){
00302       x_k = ublas::subrange(x_prev,i*t_size,(i+1)*t_size);
00303       h_i = rtslam::quaternion::composeFrames(h_i, x_k);
00304     }
00305     // evaluate H_i
00306     h_k = jblas::zero_vec(t_size);
00307     for(unsigned int i=0; i < t_pair_vector.size(); ++i)
00308     {
00309       x_k = ublas::subrange(x_prev,i*t_size,(i+1)*t_size);
00310       h_k = rtslam::quaternion::composeFrames(h_k,x_k);
00311 
00312       h_k_inv = rtslam::quaternion::invertFrame(h_k);
00313       h_k_inv_h_i = rtslam::quaternion::composeFrames(h_k_inv,h_i);
00314       rtslam::quaternion::composeFrames(h_k, h_k_inv_h_i, dummy_C, J_1, dummy_J); // get J_1
00315 
00316       x_k_inv = rtslam::quaternion::invertFrame(x_k);
00317       h_k_x_k_inv = rtslam::quaternion::composeFrames(h_k,x_k_inv);
00318       rtslam::quaternion::composeFrames(h_k_x_k_inv, x_k,dummy_C, dummy_J, J_2); // get J_2
00319 
00320       ublas::subrange(H_i,0,t_size,i*t_size,(i+1)*t_size) = ublas::prod(J_1,J_2); // put dh/dx_i in the correct position in H_i
00321     }
00322 
00323     // evaluate x_( i+1 ) = x_u + P_u*(H_i.transp()) * (H_i*P_u*H_I.transp()).inv() * (H_i*(x_i - x_u) - h_i)
00324     //                            \_______e________/   \__________d_________/              \____a____/
00325     //                                                 \__________d_inv___________/   \_______b______/
00326     //                            \________________________f______________________/   \___________c_________/
00327     //                            \_________________________________g_______________________________________/
00328     //                      \__________________________________x_pos________________________________________/
00329     a = x_prev - x_u;
00330     b = ublas::prod(H_i,a);
00331     c = b - h_i;
00332     d = jmath::ublasExtra::prod_JPJt(P_u,H_i);
00333     jmath::ublasExtra::lu_inv(d, d_inv);
00334     e = ublas::prod(P_u,ublas::trans(H_i));
00335     f = ublas::prod(e,d_inv);
00336     g = ublas::prod(f,c);
00337     x_pos = x_u + g;
00338 
00340     if( ublas::norm_2(x_pos - x_prev) < threshold)
00341       converged = true;
00342 
00343     x_prev = x_pos;
00344   }
00345 
00346   // store optimized transformations in the edges
00347   for(unsigned int i=0; i < t_pair_vector.size(); ++i)
00348   {
00349     t_pair_vector[i].second.x() = ublas::subrange(x_pos,i*t_size,(i+1)*t_size);
00350 //    t_pair_vector[i].second.P() = ???; //Is it needed?
00351   }
00352 }
00353 
00354 template<class VecG, class VecL, class VecC, class CovMatG, class CovMatL, class CovMatC>
00355 void composeFramesWithCov(const VecG & G, const VecL & L, VecC & C,
00356               const CovMatG & PG, const CovMatL & PL, CovMatC & PC){
00357 
00358   jblas::mat C_g(7,7), C_l(7,7);
00359   rtslam::quaternion::composeFrames(G, L, C, C_g, C_l);
00360   PC = jmath::ublasExtra::prod_JPJt(PG,C_g) +
00361      jmath::ublasExtra::prod_JPJt(PL,C_l);
00362 }
00363 
00364 } // namespace graphmap
00365 } // namespace jafar
00366 
00367 #endif // ALGORITHMS_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on Wed Oct 15 2014 00:37:20 for Jafar by doxygen 1.7.6.1
LAAS-CNRS