g2o
graph_optimizer_sparse_online.cpp
Go to the documentation of this file.
1 // g2o - General Graph Optimization
2 // Copyright (C) 2011 R. Kuemmerle, G. Grisetti, 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 "types_slam2d_online.h"
28 #include "types_slam3d_online.h"
29 
31 
32 #include "g2o/stuff/macros.h"
33 #include "g2o/core/block_solver.h"
36 
39 
40 
41 #include <iostream>
42 #include <iomanip>
43 #include <fstream>
44 using namespace std;
45 using namespace Eigen;
46 
47 #define DIM_TO_SOLVER(p, l) BlockSolver< BlockSolverTraits<p, l> >
48 
49 #define ALLOC_PCG(s, p, l) \
50  if (1) { \
51  std::cerr << "# Using PCG online poseDim " << p << " landMarkDim " << l << " blockordering 1" << std::endl; \
52  LinearSolverPCG< DIM_TO_SOLVER(p, l)::PoseMatrixType >* linearSolver = new LinearSolverPCG<DIM_TO_SOLVER(p, l)::PoseMatrixType>(); \
53  linearSolver->setMaxIterations(6); \
54  s = new DIM_TO_SOLVER(p, l)(linearSolver); \
55  } else (void)0
56 
57 namespace g2o {
58 
59  // force linking to the cholmod solver
61 
62 SparseOptimizerOnline::SparseOptimizerOnline(bool pcg) :
64  slamDimension(3), newEdges(0), batchStep(true), vizWithGnuplot(false),
65  _gnuplot(0), _usePcg(pcg), _underlyingSolver(0)
66 {
67 }
68 
70 {
71  if (_gnuplot) {
72 #ifdef WINDOWS
73  _pclose(_gnuplot);
74 #else
75  pclose(_gnuplot);
76 #endif
77  }
78 }
79 
80 int SparseOptimizerOnline::optimize(int iterations, bool online)
81 {
82  //return SparseOptimizer::optimize(iterations, online);
83 
84  (void) iterations; // we only do one iteration anyhow
86 
87  int cjIterations=0;
88  bool ok=true;
89 
90  solver->init(online);
91  if (!online) {
93  if (! ok) {
94  cerr << __PRETTY_FUNCTION__ << ": Failure while building CCS structure" << endl;
95  return 0;
96  }
97  }
98 
99  if (_usePcg)
100  batchStep = true;
101 
102  if (! online || batchStep) {
103  //cerr << "BATCH" << endl;
104  //_underlyingSolver->buildStructure();
105  // copy over the updated estimate as new linearization point
106  if (slamDimension == 3) {
107  for (size_t i = 0; i < indexMapping().size(); ++i) {
108  OnlineVertexSE2* v = static_cast<OnlineVertexSE2*>(indexMapping()[i]);
110  }
111  }
112  else if (slamDimension == 6) {
113  for (size_t i=0; i < indexMapping().size(); ++i) {
114  OnlineVertexSE3* v = static_cast<OnlineVertexSE3*>(indexMapping()[i]);
116  }
117  }
118 
120  //SparseOptimizer::linearizeSystem();
122  }
123  else {
124  //cerr << "UPDATE" << endl;
125  // compute the active errors for the required edges
126  for (HyperGraph::EdgeSet::iterator it = newEdges->begin(); it != newEdges->end(); ++it) {
127  OptimizableGraph::Edge * e = static_cast<OptimizableGraph::Edge*>(*it);
128  e->computeError();
129  }
130  // linearize the constraints and update the Hessian
131  for (HyperGraph::EdgeSet::iterator it = newEdges->begin(); it != newEdges->end(); ++it) {
132  OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
135  }
136  // update the b vector
137  for (int i = 0; i < static_cast<int>(indexMapping().size()); ++i) {
139  int iBase = v->colInHessian();
140  v->copyB(_underlyingSolver->b() + iBase);
141  }
142  }
143  ok = _underlyingSolver->solve();
145 
146  ++cjIterations;
147 
148  if (verbose()){
150  cerr
151  << "nodes = " << vertices().size()
152  << "\t edges= " << _activeEdges.size()
153  << "\t chi2= " << FIXED(activeChi2())
154  << endl;
155  }
156 
157  if (vizWithGnuplot)
159 
160  if (! ok)
161  return 0;
162  return 1;
163 }
164 
166 {
167  if (slamDimension == 3) {
168  for (size_t i=0; i < _ivMap.size(); ++i) {
169  OnlineVertexSE2* v= static_cast<OnlineVertexSE2*>(_ivMap[i]);
170  v->oplusUpdatedEstimate(update);
171  update += 3;
172  }
173  }
174  else if (slamDimension == 6) {
175  for (size_t i=0; i < _ivMap.size(); ++i) {
176  OnlineVertexSE3* v= static_cast<OnlineVertexSE3*>(_ivMap[i]);
177  v->oplusUpdatedEstimate(update);
178  update += 6;
179  }
180  }
181 }
182 
184 {
185  newEdges = &eset;
186  bool result = SparseOptimizer::updateInitialization(vset, eset);
187  for (HyperGraph::VertexSet::iterator it = vset.begin(); it != vset.end(); ++it) {
188  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it);
189  v->clearQuadraticForm(); // be sure that b is zero for this vertex
190  }
191  return result;
192 }
193 
194 static Solver* createSolver(const std::string& solverName)
195 {
196  g2o::Solver* s = 0;
197  if (solverName == "pcg3_2") {
198  ALLOC_PCG(s, 3, 2);
199  }
200  else if (solverName == "pcg6_3") {
201  ALLOC_PCG(s, 6, 3);
202  }
203  return s;
204 }
205 
206 bool SparseOptimizerOnline::initSolver(int dimension, int /*batchEveryN*/)
207 {
208  slamDimension = dimension;
210  OptimizationAlgorithmProperty solverProperty;
211  if (_usePcg) {
212  Solver* s = 0;
213  if (dimension == 3) {
214  s = createSolver("pcg3_2");
215  } else {
216  s = createSolver("pcg6_3");
217  }
219  setAlgorithm(gaussNewton);
220  }
221  else {
222  if (dimension == 3) {
223  setAlgorithm(solverFactory->construct("gn_fix3_2_cholmod", solverProperty));
224  } else {
225  setAlgorithm(solverFactory->construct("gn_fix6_3_cholmod", solverProperty));
226  }
227  }
228 
230  _underlyingSolver = gaussNewton->solver();
231 
232  if (! solver()) {
233  cerr << "Error allocating solver. Allocating CHOLMOD solver failed!" << endl;
234  return false;
235  }
236  return true;
237 }
238 
240 {
241  if (slamDimension == 3) {
242  if (! _gnuplot) {
243 #ifdef WINDOWS
244  _gnuplot = _popen("gnuplot -persistent", "w");
245 #else
246  _gnuplot = popen("gnuplot -persistent", "w");
247 #endif
248  if (_gnuplot == 0)
249  return;
250  fprintf(_gnuplot, "set terminal X11 noraise\n");
251  fprintf(_gnuplot, "set size ratio -1\n");
252  }
253  fprintf(_gnuplot, "plot \"-\" w l\n");
254  for (EdgeSet::iterator it = edges().begin(); it != edges().end(); ++it) {
255  OnlineEdgeSE2* e = (OnlineEdgeSE2*) *it;
256  OnlineVertexSE2* v1 = (OnlineVertexSE2*) e->vertices()[0];
257  OnlineVertexSE2* v2 = (OnlineVertexSE2*) e->vertices()[1];
258  fprintf(_gnuplot, "%f %f\n", v1->updatedEstimate.translation().x(), v1->updatedEstimate.translation().y());
259  fprintf(_gnuplot, "%f %f\n\n", v2->updatedEstimate.translation().x(), v2->updatedEstimate.translation().y());
260  }
261  fprintf(_gnuplot, "e\n");
262  }
263  if (slamDimension == 6) {
264  if (! _gnuplot) {
265 #ifdef WINDOWS
266  _gnuplot = _popen("gnuplot -persistent", "w");
267 #else
268  _gnuplot = popen("gnuplot -persistent", "w");
269 #endif
270  if (_gnuplot == 0)
271  return;
272  fprintf(_gnuplot, "set terminal X11 noraise\n");
273  }
274  fprintf(_gnuplot, "splot \"-\" w l\n");
275  for (EdgeSet::iterator it = edges().begin(); it != edges().end(); ++it) {
276  OnlineEdgeSE3* e = (OnlineEdgeSE3*) *it;
277  OnlineVertexSE3* v1 = (OnlineVertexSE3*) e->vertices()[0];
278  OnlineVertexSE3* v2 = (OnlineVertexSE3*) e->vertices()[1];
279  fprintf(_gnuplot, "%f %f %f\n", v1->updatedEstimate.translation().x(), v1->updatedEstimate.translation().y(), v1->updatedEstimate.translation().z());
280  fprintf(_gnuplot, "%f %f %f \n\n\n", v2->updatedEstimate.translation().x(), v2->updatedEstimate.translation().y(), v2->updatedEstimate.translation().z());
281  }
282  fprintf(_gnuplot, "e\n");
283  }
284 }
285 
286 } // end namespace
virtual bool updateInitialization(HyperGraph::VertexSet &vset, HyperGraph::EdgeSet &eset)
VertexContainer _ivMap
#define __PRETTY_FUNCTION__
Definition: macros.h:89
describe the properties of a solver
static OptimizationAlgorithm * createSolver(const std::string &solverName)
virtual int copyB(double *b_) const =0
G2O_USE_OPTIMIZATION_LIBRARY(csparse)
std::set< Vertex * > VertexSet
Definition: hyper_graph.h:136
virtual bool init(bool online=false)=0
OptimizationAlgorithm * solver()
virtual void linearizeOplus(JacobianWorkspace &jacobianWorkspace)=0
create solvers based on their short name
const VertexIDMap & vertices() const
Definition: hyper_graph.h:225
Implementation of the Gauss Newton Algorithm.
JacobianWorkspace & jacobianWorkspace()
the workspace for storing the Jacobians of the graph
int optimize(int iterations, bool online=false)
std::set< Edge * > EdgeSet
Definition: hyper_graph.h:135
const VertexContainer & vertices() const
Definition: hyper_graph.h:178
virtual void constructQuadraticForm()=0
int colInHessian() const
get the row of this vertex in the Hessian
const EdgeSet & edges() const
Definition: hyper_graph.h:230
virtual void computeError()=0
Generic interface for a sparse solver operating on a graph which solves one iteration of the lineariz...
Definition: solver.h:44
void setAlgorithm(OptimizationAlgorithm *algorithm)
const VertexContainer & indexMapping() const
the index mapping of the vertices
EdgeContainer _activeEdges
sorted according to EdgeIDCompare
virtual bool solve()=0
virtual void clearQuadraticForm()=0
void setEstimate(const EstimateType &et)
set the estimate for the vertex also calls updateCache()
Definition: base_vertex.h:101
#define ALLOC_PCG(s, p, l)
A general case Vertex for optimization.
double * x()
return x, the solution vector
Definition: solver.h:96
static OptimizationAlgorithmFactory * instance()
return the instance
double * b()
return b, the right hand side of the system
Definition: solver.h:99
virtual bool buildSystem()=0
void oplusUpdatedEstimate(double *update)
VertexSE2::EstimateType updatedEstimate
virtual bool initSolver(int dimension, int batchEveryN)
void oplusUpdatedEstimate(double *update)
Generic interface for a non-linear solver operating on a graph.
const Vector2D & translation() const
translational component
Definition: se2.h:54
virtual bool updateInitialization(HyperGraph::VertexSet &vset, HyperGraph::EdgeSet &eset)
VertexSE3::EstimateType updatedEstimate
bool verbose() const
verbose information during optimization
OptimizationAlgorithm * construct(const std::string &tag, OptimizationAlgorithmProperty &solverProperty) const
OptimizationAlgorithm * _algorithm
virtual bool buildStructure(bool zeroBlocks=false)=0
double activeChi2() const