g2o
simple_star_ops.cpp
Go to the documentation of this file.
1 #include "simple_star_ops.h"
2 #include "backbone_tree_action.h"
5 #include <iostream>
6 #include <Eigen/LU>
7 #include <Eigen/Cholesky>
8 #include <Eigen/Eigenvalues>
9 
10 
11 namespace g2o{
12 
13  using namespace std;
14  using namespace Eigen;
15 
17  const SparseOptimizer* s = dynamic_cast<const SparseOptimizer*>(v->graph());
19  double chi = 0;
20  int ne =0;
21  for (HyperGraph::EdgeSet::iterator it = v->edges().begin(); it!=v->edges().end(); it++){
22  OptimizableGraph::Edge* e = dynamic_cast <OptimizableGraph::Edge*> (*it);
23  if (!e)
24  continue;
25  if (s->findActiveEdge(e)!=av.end()) {
26  chi +=e->chi2();
27  ne++;
28  }
29  }
30  if (! ne)
31  return -1;
32  return chi/ne;
33  }
34 
35 void constructEdgeStarMap(EdgeStarMap& esmap, StarSet& stars, bool low){
36  esmap.clear();
37  for (StarSet::iterator it=stars.begin(); it!=stars.end(); it++){
38  Star* s = *it;
39  if (low) {
40  for (HyperGraph::EdgeSet::iterator it = s->lowLevelEdges().begin();
41  it!=s->lowLevelEdges().end(); it++){
42  HyperGraph::Edge* e=*it;
43  esmap.insert(make_pair(e,s));
44  }
45  } else {
46  for (HyperGraph::EdgeSet::iterator it = s->starEdges().begin();
47  it!=s->starEdges().end(); it++){
48  HyperGraph::Edge* e=*it;
49  esmap.insert(make_pair(e,s));
50  }
51  }
52  }
53 }
54 
56  eset.clear();
57  for (HyperGraph::EdgeSet::iterator it=v->edges().begin(); it!=v->edges().end(); it++){
58  HyperGraph::Edge* e=*it;
59  EdgeStarMap::iterator eit=esmap.find(e);
60  if (eit!=esmap.end() && eit->second == s)
61  eset.insert(e);
62  }
63  return eset.size();
64 }
65 
67  for (HyperGraph::EdgeSet::iterator it=v->edges().begin(); it!=v->edges().end(); it++){
68  HyperGraph::Edge* e=*it;
69  EdgeStarMap::iterator eit=esmap.find(e);
70  if (eit!=esmap.end())
71  stars.insert(eit->second);
72  }
73 }
74 
76  for (size_t i=0; i<e->vertices().size(); i++){
78  if (gauge.find(v)==gauge.end())
79  starsInVertex(stars, v, esmap);
80  }
81 }
82 
83 void assignHierarchicalEdges(StarSet& stars, EdgeStarMap& esmap, EdgeLabeler* labeler, EdgeCreator* creator, SparseOptimizer* optimizer, int minNumEdges, int maxIterations){
84  // now construct the hierarchical edges for all the stars
85  int starNum=0;
86  for (StarSet::iterator it=stars.begin(); it!=stars.end(); it++){
87  cerr << "STAR# " << starNum << endl;
88  Star* s=*it;
89  std::vector<OptimizableGraph::Vertex*> vertices(2);
90  vertices[0]= (OptimizableGraph::Vertex*) *s->_gauge.begin();
91  cerr << "eIs" << endl;
93  for (HyperGraph::VertexSet::iterator vit=s->_lowLevelVertices.begin(); vit!=s->_lowLevelVertices.end(); vit++){
95  vertices[1]=v;
96  if (v==vertices[0])
97  continue;
98  HyperGraph::EdgeSet eInSt;
99  int numEdges = vertexEdgesInStar(eInSt, v, s, esmap);
100  if (Factory::instance()->tag(v)==Factory::instance()->tag(vertices[0]) || numEdges>minNumEdges) {
101  OptimizableGraph::Edge* e=creator->createEdge(vertices);
102  //cerr << "creating edge" << e << endl;
103  if (e) {
104  e->setLevel(1);
105  optimizer->addEdge(e);
106  s->_starEdges.insert(e);
107  } else {
108  cerr << "THERE" << endl;
109  cerr << "FATAL, cannot create edge" << endl;
110  }
111  } else {
112  vNew.erase(v);
113  // cerr << numEdges << " ";
114  // cerr << "r " << v-> id() << endl;
115  // remove from the star all edges that are not sufficiently connected
116  for (HyperGraph::EdgeSet::iterator it=eInSt.begin(); it!=eInSt.end(); it++){
117  HyperGraph::Edge* e=*it;
118  s->lowLevelEdges().erase(e);
119  }
120  }
121  }
122  s->lowLevelVertices()=vNew;
123  //cerr << endl;
124  cerr << "gauge: " << (*s->_gauge.begin())->id()
125  << " edges:" << s->_lowLevelEdges.size()
126  << " hedges" << s->_starEdges.size() << endl;
127 
128  const bool debug = false;
129  if (debug){
130  char starLowName[100];
131  sprintf(starLowName, "star-%04d-low.g2o", starNum);
132  ofstream starLowStream(starLowName);
133  optimizer->saveSubset(starLowStream, s->_lowLevelEdges);
134  }
135  bool labelOk=s->labelStarEdges(maxIterations, labeler);
136  if (labelOk) {
137  if (debug) {
138  char starHighName[100];
139  sprintf(starHighName, "star-%04d-high.g2o", starNum);
140  ofstream starHighStream(starHighName);
141  optimizer->saveSubset(starHighStream, s->_starEdges);
142  }
143  } else {
144  cerr << "FAILURE" << endl;
145  }
146  starNum++;
147  }
148 }
149 
150 void computeBorder(StarSet& stars, EdgeStarMap& hesmap){
151  cerr << "computing edges on the border" << endl;
152  for (StarSet::iterator it=stars.begin(); it!=stars.end(); it++){
153  Star* s=*it;
154  for (HyperGraph::EdgeSet::iterator iit=s->_starEdges.begin(); iit!=s->_starEdges.end(); iit++){
156  StarSet sset;
157  starsInEdge(sset, e, hesmap, s->gauge());
158  //cerr << "e: " << e << " l:" << e->level() << " sset.size()=" << sset.size() << endl;
159  if (sset.size()>1){
160  s->starFrontierEdges().insert(e);
161  }
162  }
163  }
164 }
165 
166 
168  SparseOptimizer* optimizer,
169  EdgeLabeler* labeler,
170  EdgeCreator* creator,
171  OptimizableGraph::Vertex* gauge_,
172  std::string edgeTag,
173  std::string vertexTag,
174  int level,
175  int step,
176  int backboneIterations,
177  int starIterations,
178  double rejectionThreshold,
179  bool debug){
180 
181  cerr << "preforming the tree actions" << endl;
182  HyperDijkstra d(optimizer);
183  // compute a spanning tree based on the types of edges and vertices in the pool
184  EdgeTypesCostFunction f(edgeTag, vertexTag, level);
185  d.shortestPaths(gauge_,
186  &f,
187  std::numeric_limits< double >::max(),
188  1e-6,
189  false,
190  std::numeric_limits< double >::max()/2);
191 
193  // constructs the stars on the backbone
194 
195  BackBoneTreeAction bact(optimizer, vertexTag, level, step);
196  bact.init();
197 
198  cerr << "free edges size " << bact.freeEdges().size() << endl;
199 
200  // perform breadth-first visit of the visit tree and create the stars on the backbone
201  d.visitAdjacencyMap(d.adjacencyMap(),&bact,true);
202  stars.clear();
203 
204  for (VertexStarMultimap::iterator it=bact.vertexStarMultiMap().begin();
205  it!=bact.vertexStarMultiMap().end(); it++){
206  stars.insert(it->second);
207  }
208  cerr << "stars.size: " << stars.size() << endl;
209  cerr << "size: " << bact.vertexStarMultiMap().size() << endl;
210 
211 
212  // for each star
213 
214  // for all vertices in the backbone, select all edges leading/leaving from that vertex
215  // that are contained in freeEdges.
216 
217  // mark the corresponding "open" vertices and add them to a multimap (vertex->star)
218 
219  // select a gauge in the backbone
220 
221  // push all vertices on the backbone
222 
223  // compute an initial guess on the backbone
224 
225  // one round of optimization backbone
226 
227  // lock all vertices in the backbone
228 
229  // push all "open" vertices
230 
231  // for each open vertex,
232  // compute an initial guess given the backbone
233  // do some rounds of solveDirect
234  // if (fail)
235  // - remove the vertex and the edges in that vertex from the star
236  // - make the structures consistent
237 
238  // pop all "open" vertices
239  // pop all "vertices" in the backbone
240  // unfix the vertices in the backbone
241 
242  int starNum=0;
243  for (StarSet::iterator it=stars.begin(); it!=stars.end(); it++){
244  Star* s =*it;
245  HyperGraph::VertexSet backboneVertices = s->_lowLevelVertices;
246  HyperGraph::EdgeSet backboneEdges = s->_lowLevelEdges;
247  if (backboneEdges.empty())
248  continue;
249 
250 
251  // cerr << "optimizing backbone" << endl;
252  // one of these should be the gauge, to be simple we select the fisrt one in the backbone
254  gauge.insert(*backboneVertices.begin());
255  s->gauge()=gauge;
256  s->optimizer()->push(backboneVertices);
257  s->optimizer()->setFixed(gauge,true);
258  s->optimizer()->initializeOptimization(backboneEdges);
260  s->optimizer()->optimize(backboneIterations);
261  s->optimizer()->setFixed(backboneVertices, true);
262 
263  // cerr << "assignind edges.vertices not in bbone" << endl;
264  HyperGraph::EdgeSet otherEdges;
265  HyperGraph::VertexSet otherVertices;
266  std::multimap<HyperGraph::Vertex*, HyperGraph::Edge*> vemap;
267  for (HyperGraph::VertexSet::iterator bit=backboneVertices.begin(); bit!=backboneVertices.end(); bit++){
268  HyperGraph::Vertex* v=*bit;
269  for (HyperGraph::EdgeSet::iterator eit=v->edges().begin(); eit!=v->edges().end(); eit++){
271  HyperGraph::EdgeSet::iterator feit=bact.freeEdges().find(e);
272  if (feit!=bact.freeEdges().end()){ // edge is admissible
273  otherEdges.insert(e);
274  bact.freeEdges().erase(feit);
275  for (size_t i=0; i<e->vertices().size(); i++){
277  if (backboneVertices.find(ve)==backboneVertices.end()){
278  otherVertices.insert(ve);
279  vemap.insert(make_pair(ve,e));
280  }
281  }
282  }
283  }
284  }
285 
286  // RAINER TODO maybe need a better solution than dynamic casting here??
287  OptimizationAlgorithmWithHessian* solverWithHessian = dynamic_cast<OptimizationAlgorithmWithHessian*>(s->optimizer()->solver());
288  if (solverWithHessian) {
289  s->optimizer()->push(otherVertices);
290  // cerr << "optimizing vertices out of bbone" << endl;
291  // cerr << "push" << endl;
292  // cerr << "init" << endl;
293  s->optimizer()->initializeOptimization(otherEdges);
294  // cerr << "guess" << endl;
296  // cerr << "solver init" << endl;
297  s->optimizer()->solver()->init();
298  // cerr << "structure" << endl;
299  if (!solverWithHessian->buildLinearStructure())
300  cerr << "FATAL: failure while building linear structure" << endl;
301  // cerr << "errors" << endl;
303  // cerr << "system" << endl;
304  solverWithHessian->updateLinearSystem();
305  // cerr << "directSolove" << endl;
306  } else {
307  cerr << "FATAL: hierarchical thing cannot be used with a solver that does not support the system structure construction" << endl;
308  }
309 
310 
311  // // then optimize the vertices one at a time to check if a solution is good
312  for (HyperGraph::VertexSet::iterator vit=otherVertices.begin(); vit!=otherVertices.end(); vit++){
314  v->solveDirect();
315  // cerr << " " << d;
316  // if a solution is found, add a vertex and all the edges in
317  //othervertices that are pointing to that edge to the star
318  s->_lowLevelVertices.insert(v);
319  for (HyperGraph::EdgeSet::iterator eit=v->edges().begin(); eit!=v->edges().end(); eit++){
321  if (otherEdges.find(e)!=otherEdges.end())
322  s->_lowLevelEdges.insert(e);
323  }
324  }
325  //cerr << endl;
326 
327  // relax the backbone and optimize it all
328  // cerr << "relax bbone" << endl;
329  s->optimizer()->setFixed(backboneVertices, false);
330  //cerr << "fox gauge bbone" << endl;
331  s->optimizer()->setFixed(s->gauge(),true);
332 
333  //cerr << "opt init" << endl;
335  optimizer->computeActiveErrors();
336  double initialChi = optimizer->activeChi2();
337  int starOptResult = s->optimizer()->optimize(starIterations);
338  //cerr << starOptResult << "(" << starIterations << ") " << endl;
339  double finalchi=-1.;
340 
341  cerr << "computing star: " << starNum << endl;
342 
343  int vKept=0, vDropped=0;
344  if (!starIterations || starOptResult > 0 ){
345  optimizer->computeActiveErrors();
346  finalchi = optimizer->activeChi2();
347 
348 #if 1
349 
351  // cerr << "system" << endl;
352  solverWithHessian->updateLinearSystem();
353  HyperGraph::EdgeSet prunedStarEdges = backboneEdges;
354  HyperGraph::VertexSet prunedStarVertices = backboneVertices;
355  for (HyperGraph::VertexSet::iterator vit=otherVertices.begin(); vit!=otherVertices.end(); vit++){
356 
357  //discard the vertices whose error is too big
358 
359 
361  MatrixXd h(v->dimension(), v->dimension());
362  for (int i=0; i<v->dimension(); i++){
363  for (int j=0; j<v->dimension(); j++)
364  h(i,j)=v->hessian(i,j);
365  }
366  EigenSolver<Eigen::MatrixXd> esolver;
367  esolver.compute(h);
368  VectorXcd ev= esolver.eigenvalues();
369  double emin = std::numeric_limits<double>::max();
370  double emax = -std::numeric_limits<double>::max();
371  for (int i=0; i<ev.size(); i++){
372  emin = ev(i).real()>emin ? emin : ev(i).real();
373  emax = ev(i).real()<emax ? emax : ev(i).real();
374  }
375 
376  double d=emin/emax;
377 
378 
379  // cerr << " " << d;
380  if (d>rejectionThreshold){
381  // if a solution is found, add a vertex and all the edges in
382  //othervertices that are pointing to that edge to the star
383  prunedStarVertices.insert(v);
384  for (HyperGraph::EdgeSet::iterator eit=v->edges().begin(); eit!=v->edges().end(); eit++){
386  if (otherEdges.find(e)!=otherEdges.end())
387  prunedStarEdges.insert(e);
388  }
389  //cerr << "K( " << v->id() << "," << d << ")" ;
390  vKept ++;
391  } else {
392  vDropped++;
393  //cerr << "R( " << v->id() << "," << d << ")" ;
394  }
395  }
396  s->_lowLevelEdges=prunedStarEdges;
397  s->_lowLevelVertices=prunedStarVertices;
398 
399 #endif
400  //cerr << "addHedges" << endl;
401  //now add to the star the hierarchical edges
402  std::vector<OptimizableGraph::Vertex*> vertices(2);
403  vertices[0]= (OptimizableGraph::Vertex*) *s->_gauge.begin();
404 
405  for (HyperGraph::VertexSet::iterator vit=s->_lowLevelVertices.begin(); vit!=s->_lowLevelVertices.end(); vit++){
407  vertices[1]=v;
408  if (v==vertices[0])
409  continue;
410  OptimizableGraph::Edge* e=creator->createEdge(vertices);
411  //rr << "creating edge" << e << Factory::instance()->tag(vertices[0]) << "->" << Factory::instance()->tag(v) <endl;
412  if (e) {
413  e->setLevel(level+1);
414  optimizer->addEdge(e);
415  s->_starEdges.insert(e);
416  } else {
417  cerr << "HERE" << endl;
418  cerr << "FATAL, cannot create edge" << endl;
419  }
420  }
421  }
422 
423  cerr << " gauge: " << (*s->_gauge.begin())->id()
424  << " kept: " << vKept
425  << " dropped: " << vDropped
426  << " edges:" << s->_lowLevelEdges.size()
427  << " hedges" << s->_starEdges.size()
428  << " initial chi " << initialChi
429  << " final chi " << finalchi << endl;
430 
431  if (debug) {
432  char starLowName[100];
433  sprintf(starLowName, "star-%04d-low.g2o", starNum);
434  ofstream starLowStream(starLowName);
435  optimizer->saveSubset(starLowStream, s->_lowLevelEdges);
436  }
437  bool labelOk=false;
438  if (!starIterations || starOptResult > 0)
439  labelOk = s->labelStarEdges(0, labeler);
440  if (labelOk) {
441  if (debug) {
442  char starHighName[100];
443  sprintf(starHighName, "star-%04d-high.g2o", starNum);
444  ofstream starHighStream(starHighName);
445  optimizer->saveSubset(starHighStream, s->_starEdges);
446  }
447  } else {
448 
449  cerr << "FAILURE: " << starOptResult << endl;
450  }
451  starNum++;
452 
453  //label each hierarchical edge
454  s->optimizer()->pop(otherVertices);
455  s->optimizer()->pop(backboneVertices);
456  s->optimizer()->setFixed(s->gauge(),false);
457  }
458 
459 
460  StarSet stars2;
461  // now erase the stars that have 0 edges. They r useless
462  for (StarSet::iterator it=stars.begin(); it!=stars.end(); it++){
463  Star* s=*it;
464  if (s->lowLevelEdges().size()==0) {
465  delete s;
466  } else
467  stars2.insert(s);
468  }
469  stars=stars2;
470  }
471 
472 
473 }
virtual void computeInitialGuess()
const OptimizableGraph * graph() const
static Factory * instance()
return the instance
Definition: factory.cpp:61
SparseOptimizer * optimizer()
returns the optimizer
Definition: star.h:41
virtual double solveDirect(double lambda=0)=0
HyperGraph::EdgeSet _lowLevelEdges
edges in the lower level
Definition: star.h:58
virtual const double & hessian(int i, int j) const =0
get the element from the hessian matrix
void assignHierarchicalEdges(StarSet &stars, EdgeStarMap &esmap, EdgeLabeler *labeler, EdgeCreator *creator, SparseOptimizer *optimizer, int minNumEdges, int maxIterations)
double activeVertexChi(const OptimizableGraph::Vertex *v)
static void computeTree(AdjacencyMap &amap)
void constructEdgeStarMap(EdgeStarMap &esmap, StarSet &stars, bool low)
std::set< Vertex * > VertexSet
Definition: hyper_graph.h:136
HyperGraph::EdgeSet & starFrontierEdges()
edges in the high level that lead to some node owned by a different star
Definition: star.h:47
void pop(SparseOptimizer::VertexContainer &vlist)
pop (restore) the estimate a subset of the variables from the stack
virtual double chi2() const =0
computes the chi2 based on the cached error value, only valid after computeError has been called...
int optimize(int iterations, bool online=false)
HyperGraph::EdgeSet & starEdges()
high level edge set
Definition: star.h:45
virtual bool init(bool online=false)=0
OptimizationAlgorithm * solver()
const EdgeContainer & activeEdges() const
the edges active in the current optimization
Base for solvers operating on the approximated Hessian, e.g., Gauss-Newton, Levenberg.
void computeBorder(StarSet &stars, EdgeStarMap &hesmap)
bool labelStarEdges(int iterations, EdgeLabeler *labeler)
Definition: star.cpp:9
std::vector< OptimizableGraph::Edge * > EdgeContainer
vector container for edges
std::set< Edge * > EdgeSet
Definition: hyper_graph.h:135
static void visitAdjacencyMap(AdjacencyMap &amap, TreeAction *action, bool useDistance=false)
int dimension() const
dimension of the estimated state belonging to this node
Protocol The SLAM executable accepts such as solving the and retrieving or vertices in the explicitly state the reprensentation poses are represented by poses by VERTEX_XYZRPY In the Quaternions and other representations could be but note that it is up to the SLAM algorithm to choose the internal representation of the angles The keyword is followed by a unique vertex ID and an optional initialization of the or edges in the explicitly state the type of the constraint pose constraints are given by pose constraints by EDGE_XYZRPY The keyword is followed by a unique edge the IDs of the referenced vertices
Definition: protocol.txt:7
HyperGraph::EdgeSet _starEdges
edges in the star
Definition: star.h:60
const VertexContainer & vertices() const
Definition: hyper_graph.h:178
const EdgeSet & edges() const
returns the set of hyper-edges that are leaving/entering in this vertex
Definition: hyper_graph.h:151
void shortestPaths(HyperGraph::Vertex *v, HyperDijkstra::CostFunction *cost, double maxDistance=std::numeric_limits< double >::max(), double comparisonConditioner=1e-3, bool directed=false, double maxEdgeCost=std::numeric_limits< double >::max())
Definition: star.h:26
bool saveSubset(std::ostream &os, HyperGraph::VertexSet &vset, int level=0)
save a subgraph to a stream. Again uses the Factory system.
HyperGraph::VertexSet _lowLevelVertices
vertices that are fixed (center of the star)
Definition: star.h:66
std::set< Star * > StarSet
Definition: star.h:71
HyperGraph::VertexSet _gauge
vertices that are fixed (center of the star)
Definition: star.h:64
void starsInEdge(StarSet &stars, HyperGraph::Edge *e, EdgeStarMap &esmap, HyperGraph::VertexSet &gauge)
OptimizableGraph::Edge * createEdge(std::vector< OptimizableGraph::Vertex * > &vertices)
std::map< HyperGraph::Edge *, Star * > EdgeStarMap
Definition: star.h:72
void starsInVertex(StarSet &stars, HyperGraph::Vertex *v, EdgeStarMap &esmap)
A general case Vertex for optimization.
abstract Vertex, your types must derive from that one
Definition: hyper_graph.h:142
HyperGraph::EdgeSet & lowLevelEdges()
low level edge set
Definition: star.h:43
EdgeContainer::const_iterator findActiveEdge(const OptimizableGraph::Edge *e) const
AdjacencyMap & adjacencyMap()
size_t vertexEdgesInStar(HyperGraph::EdgeSet &eset, HyperGraph::Vertex *v, Star *s, EdgeStarMap &esmap)
virtual void setFixed(HyperGraph::VertexSet &vset, bool fixed)
fixes/releases a set of vertices
void computeSimpleStars(StarSet &stars, SparseOptimizer *optimizer, EdgeLabeler *labeler, EdgeCreator *creator, OptimizableGraph::Vertex *gauge_, std::string edgeTag, std::string vertexTag, int level, int step, int backboneIterations, int starIterations, double rejectionThreshold, bool debug)
HyperGraph::VertexSet & gauge()
set of nodes to keep fixed in the optimization
Definition: star.h:49
void setLevel(int l)
sets the level of the edge
virtual bool initializeOptimization(HyperGraph::EdgeSet &eset)
void push(SparseOptimizer::VertexContainer &vlist)
push the estimate of a subset of the variables onto a stack
virtual bool addEdge(HyperGraph::Edge *e)
yylloc step()
HyperGraph::VertexSet & lowLevelVertices()
set of all vertices in the low level
Definition: star.h:51
double activeChi2() const