g2o
Loading...
Searching...
No Matches
simple_star_ops.cpp
Go to the documentation of this file.
1// g2o - General Graph Optimization
2// Copyright (C) 2011 R. Kuemmerle, G. Grisetti, H. Strasdat, W. Burgard
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright notice,
10// this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
18// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27#include "simple_star_ops.h"
28
29#include <Eigen/Cholesky>
30#include <Eigen/Eigenvalues>
31#include <Eigen/LU>
32#include <cassert>
33#include <iostream>
34
38
39namespace g2o {
40
41using namespace std;
42using namespace Eigen;
43
45 const SparseOptimizer* s = dynamic_cast<const SparseOptimizer*>(v->graph());
47 double chi = 0;
48 int ne = 0;
49 for (HyperGraph::EdgeSet::iterator it = v->edges().begin();
50 it != v->edges().end(); ++it) {
51 OptimizableGraph::Edge* e = dynamic_cast<OptimizableGraph::Edge*>(*it);
52 if (!e) continue;
53 if (s->findActiveEdge(e) != av.end()) {
54 chi += e->chi2();
55 ne++;
56 }
57 }
58 if (!ne) return -1;
59 return chi / ne;
60}
61
62void constructEdgeStarMap(EdgeStarMap& esmap, StarSet& stars, bool low) {
63 esmap.clear();
64 for (StarSet::iterator it = stars.begin(); it != stars.end(); ++it) {
65 Star* s = *it;
66 if (low) {
67 for (HyperGraph::EdgeSet::iterator it = s->lowLevelEdges().begin();
68 it != s->lowLevelEdges().end(); ++it) {
69 HyperGraph::Edge* e = *it;
70 esmap.insert(make_pair(e, s));
71 }
72 } else {
73 for (HyperGraph::EdgeSet::iterator it = s->starEdges().begin();
74 it != s->starEdges().end(); ++it) {
75 HyperGraph::Edge* e = *it;
76 esmap.insert(make_pair(e, s));
77 }
78 }
79 }
80}
81
83 Star* s, EdgeStarMap& esmap) {
84 eset.clear();
85 for (HyperGraph::EdgeSet::iterator it = v->edges().begin();
86 it != v->edges().end(); ++it) {
87 HyperGraph::Edge* e = *it;
88 EdgeStarMap::iterator eit = esmap.find(e);
89 if (eit != esmap.end() && eit->second == s) eset.insert(e);
90 }
91 return eset.size();
92}
93
95 for (HyperGraph::EdgeSet::iterator it = v->edges().begin();
96 it != v->edges().end(); ++it) {
97 HyperGraph::Edge* e = *it;
98 EdgeStarMap::iterator eit = esmap.find(e);
99 if (eit != esmap.end()) stars.insert(eit->second);
100 }
101}
102
104 HyperGraph::VertexSet& gauge) {
105 for (size_t i = 0; i < e->vertices().size(); i++) {
107 if (gauge.find(v) == gauge.end()) starsInVertex(stars, v, esmap);
108 }
109}
110
112 EdgeLabeler* labeler, EdgeCreator* creator,
113 SparseOptimizer* optimizer, int minNumEdges,
114 int maxIterations) {
115 // now construct the hierarchical edges for all the stars
116 for (StarSet::iterator it = stars.begin(); it != stars.end(); ++it) {
117 Star* s = *it;
118 std::vector<OptimizableGraph::Vertex*> vertices(2);
119 vertices[0] = (OptimizableGraph::Vertex*)*s->_gauge.begin();
121 for (HyperGraph::VertexSet::iterator vit = s->_lowLevelVertices.begin();
122 vit != s->_lowLevelVertices.end(); ++vit) {
124 vertices[1] = v;
125 if (v == vertices[0]) continue;
127 int numEdges = vertexEdgesInStar(eInSt, v, s, esmap);
128 if (Factory::instance()->tag(v) ==
129 Factory::instance()->tag(vertices[0]) ||
130 numEdges > minNumEdges) {
131 OptimizableGraph::Edge* e = creator->createEdge(vertices);
132 // cerr << "creating edge" << e << endl;
133 if (e) {
134 e->setLevel(1);
135 optimizer->addEdge(e);
136 s->_starEdges.insert(e);
137 }
138 } else {
139 vNew.erase(v);
140 // remove from the star all edges that are not sufficiently connected
141 for (HyperGraph::EdgeSet::iterator it = eInSt.begin();
142 it != eInSt.end(); ++it) {
143 HyperGraph::Edge* e = *it;
144 s->lowLevelEdges().erase(e);
145 }
146 }
147 }
148 s->lowLevelVertices() = vNew;
149
150 bool labelOk = s->labelStarEdges(maxIterations, labeler);
151 assert(labelOk);
152 (void)labelOk;
153 }
154}
155
156void computeBorder(StarSet& stars, EdgeStarMap& hesmap) {
157 for (StarSet::iterator it = stars.begin(); it != stars.end(); ++it) {
158 Star* s = *it;
159 for (HyperGraph::EdgeSet::iterator iit = s->_starEdges.begin();
160 iit != s->_starEdges.end(); ++iit) {
162 StarSet sset;
163 starsInEdge(sset, e, hesmap, s->gauge());
164 // cerr << "e: " << e << " l:" << e->level() << " sset.size()=" <<
165 // sset.size() << endl;
166 if (sset.size() > 1) {
167 s->starFrontierEdges().insert(e);
168 }
169 }
170 }
171}
172
174 EdgeLabeler* labeler, EdgeCreator* creator,
175 OptimizableGraph::Vertex* gauge_, std::string edgeTag,
176 std::string vertexTag, int level, int step,
177 int backboneIterations, int starIterations,
178 double rejectionThreshold, bool debug) {
179 HyperDijkstra d(optimizer);
180 // compute a spanning tree based on the types of edges and vertices in the
181 // pool
182 EdgeTypesCostFunction f(edgeTag, vertexTag, level);
183 d.shortestPaths(gauge_, &f, std::numeric_limits<double>::max(), 1e-6, false,
184 std::numeric_limits<double>::max() / 2);
185
187 // constructs the stars on the backbone
188
189 BackBoneTreeAction bact(optimizer, vertexTag, level, step);
190 bact.init();
191
192 // perform breadth-first visit of the visit tree and create the stars on the
193 // backbone
194 d.visitAdjacencyMap(d.adjacencyMap(), &bact, true);
195 stars.clear();
196
197 for (VertexStarMultimap::iterator it = bact.vertexStarMultiMap().begin();
198 it != bact.vertexStarMultiMap().end(); ++it) {
199 stars.insert(it->second);
200 }
201
202 // for each star
203
204 // for all vertices in the backbone, select all edges leading/leaving from
205 // that vertex that are contained in freeEdges.
206
207 // mark the corresponding "open" vertices and add them to a multimap
208 // (vertex->star)
209
210 // select a gauge in the backbone
211
212 // push all vertices on the backbone
213
214 // compute an initial guess on the backbone
215
216 // one round of optimization backbone
217
218 // lock all vertices in the backbone
219
220 // push all "open" vertices
221
222 // for each open vertex,
223 // compute an initial guess given the backbone
224 // do some rounds of solveDirect
225 // if (fail)
226 // - remove the vertex and the edges in that vertex from the star
227 // - make the structures consistent
228
229 // pop all "open" vertices
230 // pop all "vertices" in the backbone
231 // unfix the vertices in the backbone
232
233 int starNum = 0;
234 for (StarSet::iterator it = stars.begin(); it != stars.end(); ++it) {
235 Star* s = *it;
236 HyperGraph::VertexSet backboneVertices = s->_lowLevelVertices;
237 HyperGraph::EdgeSet backboneEdges = s->_lowLevelEdges;
238 if (backboneEdges.empty()) continue;
239
240 // cerr << "optimizing backbone" << endl;
241 // one of these should be the gauge, to be simple we select the first one
242 // in the backbone
244 gauge.insert(*backboneVertices.begin());
245 s->gauge() = gauge;
246 s->optimizer()->push(backboneVertices);
247 s->optimizer()->setFixed(gauge, true);
248 s->optimizer()->initializeOptimization(backboneEdges);
250 s->optimizer()->optimize(backboneIterations);
251 s->optimizer()->setFixed(backboneVertices, true);
252
253 // cerr << "assignind edges.vertices not in bbone" << endl;
254 HyperGraph::EdgeSet otherEdges;
255 HyperGraph::VertexSet otherVertices;
256 std::multimap<HyperGraph::Vertex*, HyperGraph::Edge*> vemap;
257 for (HyperGraph::VertexSet::iterator bit = backboneVertices.begin();
258 bit != backboneVertices.end(); ++bit) {
259 HyperGraph::Vertex* v = *bit;
260 for (HyperGraph::EdgeSet::iterator eit = v->edges().begin();
261 eit != v->edges().end(); ++eit) {
263 HyperGraph::EdgeSet::iterator feit = bact.freeEdges().find(e);
264 if (feit != bact.freeEdges().end()) { // edge is admissible
265 otherEdges.insert(e);
266 bact.freeEdges().erase(feit);
267 for (size_t i = 0; i < e->vertices().size(); i++) {
270 if (backboneVertices.find(ve) == backboneVertices.end()) {
271 otherVertices.insert(ve);
272 vemap.insert(make_pair(ve, e));
273 }
274 }
275 }
276 }
277 }
278
279 // RAINER TODO maybe need a better solution than dynamic casting here??
280 OptimizationAlgorithmWithHessian* solverWithHessian =
282 s->optimizer()->solver());
283 if (solverWithHessian) {
284 s->optimizer()->push(otherVertices);
285 // cerr << "optimizing vertices out of bbone" << endl;
286 // cerr << "push" << endl;
287 // cerr << "init" << endl;
288 s->optimizer()->initializeOptimization(otherEdges);
289 // cerr << "guess" << endl;
291 // cerr << "solver init" << endl;
292 s->optimizer()->solver()->init();
293 // cerr << "structure" << endl;
294 if (!solverWithHessian->buildLinearStructure())
295 cerr << "FATAL: failure while building linear structure" << endl;
296 // cerr << "errors" << endl;
298 // cerr << "system" << endl;
299 solverWithHessian->updateLinearSystem();
300 // cerr << "directSolove" << endl;
301 } else {
302 cerr << "FATAL: hierarchical thing cannot be used with a solver that "
303 "does not support the system structure "
304 "construction"
305 << endl;
306 }
307
308 // // then optimize the vertices one at a time to check if a solution is
309 // good
310 for (HyperGraph::VertexSet::iterator vit = otherVertices.begin();
311 vit != otherVertices.end(); ++vit) {
313 v->solveDirect();
314 // cerr << " " << d;
315 // if a solution is found, add a vertex and all the edges in
316 // othervertices that are pointing to that edge to the star
317 s->_lowLevelVertices.insert(v);
318 for (HyperGraph::EdgeSet::iterator eit = v->edges().begin();
319 eit != v->edges().end(); ++eit) {
321 if (otherEdges.find(e) != otherEdges.end()) s->_lowLevelEdges.insert(e);
322 }
323 }
324 // cerr << endl;
325
326 // relax the backbone and optimize it all
327 // cerr << "relax bbone" << endl;
328 s->optimizer()->setFixed(backboneVertices, false);
329 // cerr << "fox gauge bbone" << endl;
330 s->optimizer()->setFixed(s->gauge(), true);
331
332 // cerr << "opt init" << endl;
334 optimizer->computeActiveErrors();
335 int starOptResult = s->optimizer()->optimize(starIterations);
336 // cerr << starOptResult << "(" << starIterations << ") " << endl;
337
338 if (!starIterations || starOptResult > 0) {
339 optimizer->computeActiveErrors();
340
341#if 1
342
344 // cerr << "system" << endl;
345 if (solverWithHessian) solverWithHessian->updateLinearSystem();
346 HyperGraph::EdgeSet prunedStarEdges = backboneEdges;
347 HyperGraph::VertexSet prunedStarVertices = backboneVertices;
348 for (HyperGraph::VertexSet::iterator vit = otherVertices.begin();
349 vit != otherVertices.end(); ++vit) {
350 // discard the vertices whose error is too big
351
353 MatrixXd h(v->dimension(), v->dimension());
354 for (int i = 0; i < v->dimension(); i++) {
355 for (int j = 0; j < v->dimension(); j++) h(i, j) = v->hessian(i, j);
356 }
357 EigenSolver<Eigen::MatrixXd> esolver;
358 esolver.compute(h);
359 VectorXcd ev = esolver.eigenvalues();
360 double emin = std::numeric_limits<double>::max();
361 double emax = -std::numeric_limits<double>::max();
362 for (int i = 0; i < ev.size(); i++) {
363 emin = ev(i).real() > emin ? emin : ev(i).real();
364 emax = ev(i).real() < emax ? emax : ev(i).real();
365 }
366
367 double d = emin / emax;
368
369 // cerr << " " << d;
370 if (d > rejectionThreshold) {
371 // if a solution is found, add a vertex and all the edges in
372 // othervertices that are pointing to that edge to the star
373 prunedStarVertices.insert(v);
374 for (HyperGraph::EdgeSet::iterator eit = v->edges().begin();
375 eit != v->edges().end(); ++eit) {
377 if (otherEdges.find(e) != otherEdges.end())
378 prunedStarEdges.insert(e);
379 }
380 // cerr << "K( " << v->id() << "," << d << ")" ;
381 }
382 }
383 s->_lowLevelEdges = prunedStarEdges;
384 s->_lowLevelVertices = prunedStarVertices;
385
386#endif
387 // cerr << "addHedges" << endl;
388 // now add to the star the hierarchical edges
389 std::vector<OptimizableGraph::Vertex*> vertices(2);
390 vertices[0] = (OptimizableGraph::Vertex*)*s->_gauge.begin();
391
392 for (HyperGraph::VertexSet::iterator vit = s->_lowLevelVertices.begin();
393 vit != s->_lowLevelVertices.end(); ++vit) {
395 vertices[1] = v;
396 if (v == vertices[0]) continue;
397 OptimizableGraph::Edge* e = creator->createEdge(vertices);
398 // rr << "creating edge" << e << Factory::instance()->tag(vertices[0])
399 // << "->" << Factory::instance()->tag(v) <endl;
400 if (e) {
401 e->setLevel(level + 1);
402 optimizer->addEdge(e);
403 s->_starEdges.insert(e);
404 }
405 }
406 }
407
408 if (debug) {
409 char starLowName[100];
410 snprintf(starLowName, 99, "star-%04d-low.g2o", starNum);
411 ofstream starLowStream(starLowName);
412 optimizer->saveSubset(starLowStream, s->_lowLevelEdges);
413 }
414 bool labelOk = false;
415 if (!starIterations || starOptResult > 0)
416 labelOk = s->labelStarEdges(0, labeler);
417 if (labelOk) {
418 if (debug) {
419 char starHighName[100];
420 snprintf(starHighName, 99, "star-%04d-high.g2o", starNum);
421 ofstream starHighStream(starHighName);
422 optimizer->saveSubset(starHighStream, s->_starEdges);
423 }
424 }
425 starNum++;
426
427 // label each hierarchical edge
428 s->optimizer()->pop(otherVertices);
429 s->optimizer()->pop(backboneVertices);
430 s->optimizer()->setFixed(s->gauge(), false);
431 }
432
433 StarSet stars2;
434 // now erase the stars that have 0 edges. They r useless
435 for (StarSet::iterator it = stars.begin(); it != stars.end(); ++it) {
436 Star* s = *it;
437 if (s->lowLevelEdges().size() == 0) {
438 delete s;
439 } else
440 stars2.insert(s);
441 }
442 stars = stars2;
443}
444
445} // namespace g2o
static Factory * instance()
return the instance
Definition factory.cpp:46
const VertexContainer & vertices() const
abstract Vertex, your types must derive from that one
const EdgeSet & edges() const
returns the set of hyper-edges that are leaving/entering in this vertex
std::set< Edge * > EdgeSet
std::set< Vertex * > VertexSet
virtual double chi2() const =0
void setLevel(int l)
sets the level of the edge
A general case Vertex for optimization.
virtual const double & hessian(int i, int j) const =0
get the element from the hessian matrix
virtual double solveDirect(double lambda=0)=0
int dimension() const
dimension of the estimated state belonging to this node
const OptimizableGraph * graph() const
Base for solvers operating on the approximated Hessian, e.g., Gauss-Newton, Levenberg.
virtual bool init(bool online=false)=0
void push(SparseOptimizer::VertexContainer &vlist)
push the estimate of a subset of the variables onto a stack
int optimize(int iterations, bool online=false)
const EdgeContainer & activeEdges() const
the edges active in the current optimization
EdgeContainer::const_iterator findActiveEdge(const OptimizableGraph::Edge *e) const
virtual bool initializeOptimization(HyperGraph::EdgeSet &eset)
void pop(SparseOptimizer::VertexContainer &vlist)
pop (restore) the estimate a subset of the variables from the stack
virtual void computeInitialGuess()
OptimizationAlgorithm * solver()
Definition jet.h:938
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)
double activeVertexChi(const OptimizableGraph::Vertex *v)
size_t vertexEdgesInStar(HyperGraph::EdgeSet &eset, HyperGraph::Vertex *v, Star *s, EdgeStarMap &esmap)
void computeBorder(StarSet &stars, EdgeStarMap &hesmap)
void starsInVertex(StarSet &stars, HyperGraph::Vertex *v, EdgeStarMap &esmap)
void assignHierarchicalEdges(StarSet &stars, EdgeStarMap &esmap, EdgeLabeler *labeler, EdgeCreator *creator, SparseOptimizer *optimizer, int minNumEdges, int maxIterations)
std::set< Star * > StarSet
Definition star.h:100
std::map< HyperGraph::Edge *, Star * > EdgeStarMap
Definition star.h:101
void constructEdgeStarMap(EdgeStarMap &esmap, StarSet &stars, bool low)
void starsInEdge(StarSet &stars, HyperGraph::Edge *e, EdgeStarMap &esmap, HyperGraph::VertexSet &gauge)
Definition jet.h:876
yylloc step()
HyperGraph::EdgeSet & freeEdges()
edges that are not yet assigned to any star
VertexStarMultimap & vertexStarMultiMap()
multimap vertex->star. Contains all the vertex assignments to all stars
void init()
initializes the visit and clears the internal structures
OptimizableGraph::Edge * createEdge(std::vector< OptimizableGraph::Vertex * > &vertices)
static void computeTree(AdjacencyMap &amap)
static void visitAdjacencyMap(AdjacencyMap &amap, TreeAction *action, bool useDistance=false)
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())
AdjacencyMap & adjacencyMap()
virtual void setFixed(HyperGraph::VertexSet &vset, bool fixed)
fixes/releases a set of vertices
std::vector< OptimizableGraph::Edge * > EdgeContainer
vector container for edges
virtual bool addEdge(HyperGraph::Edge *e)
bool saveSubset(std::ostream &os, HyperGraph::VertexSet &vset, int level=0)
save a subgraph to a stream. Again uses the Factory system.
bool labelStarEdges(int iterations, EdgeLabeler *labeler)
Definition star.cpp:37
HyperGraph::EdgeSet & starFrontierEdges()
edges in the high level that lead to some node owned by a different star
Definition star.h:76
HyperGraph::VertexSet _lowLevelVertices
vertices that are fixed (center of the star)
Definition star.h:95
SparseOptimizer * optimizer()
returns the optimizer
Definition star.h:70
HyperGraph::EdgeSet & lowLevelEdges()
low level edge set
Definition star.h:72
HyperGraph::VertexSet & lowLevelVertices()
set of all vertices in the low level
Definition star.h:80
HyperGraph::VertexSet _gauge
vertices that are fixed (center of the star)
Definition star.h:93
HyperGraph::EdgeSet _starEdges
edges in the star
Definition star.h:89
HyperGraph::EdgeSet & starEdges()
high level edge set
Definition star.h:74
HyperGraph::EdgeSet _lowLevelEdges
edges in the lower level
Definition star.h:87
HyperGraph::VertexSet & gauge()
set of nodes to keep fixed in the optimization
Definition star.h:78