g2o
graph_optimizer_sparse_incremental.cpp
Go to the documentation of this file.
1 // g2o - General Graph Optimization
2 // Copyright (C) 2011 R. Kuemmerle, G. Grisetti, W. Burgard
3 //
4 // g2o is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published
6 // by the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // g2o is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
18 
21 
22 #include "g2o/core/block_solver.h"
24 
25 #include "g2o/stuff/macros.h"
26 
27 #define DIM_TO_SOLVER(p, l) BlockSolver< BlockSolverTraits<p, l> >
28 
29 #define ALLOC_CHOLMOD(s, p, l) \
30  if (1) { \
31  std::cerr << "# Using CHOLMOD online poseDim " << p << " landMarkDim " << l << " blockordering 1" << std::endl; \
32  LinearSolverCholmodOnline < DIM_TO_SOLVER(p, l)::PoseMatrixType >* linearSolver = new LinearSolverCholmodOnline<DIM_TO_SOLVER(p, l)::PoseMatrixType>(); \
33  s = new DIM_TO_SOLVER(p, l)(linearSolver); \
34  } else (void)0
35 
36 using namespace std;
37 using namespace Eigen;
38 
39 namespace g2o {
40 
41  namespace {
45  struct VertexBackup
46  {
47  int hessianIndex;
48  OptimizableGraph::Vertex* vertex;
49  double* hessianData;
50  bool operator<(const VertexBackup& other) const
51  {
52  return hessianIndex < other.hessianIndex;
53  }
54  };
55  }
56 
57  SparseOptimizerIncremental::SparseOptimizerIncremental()
58  {
59  _cholmodSparse = new CholmodExt();
60  _cholmodFactor = 0;
61  cholmod_start(&_cholmodCommon);
62 
63  // setup ordering strategy to not permute the matrix
64  _cholmodCommon.nmethods = 1 ;
65  _cholmodCommon.method[0].ordering = CHOLMOD_NATURAL;
66  _cholmodCommon.postorder = 0;
67  _cholmodCommon.supernodal = CHOLMOD_SIMPLICIAL;
68 
69  _permutedUpdate = cholmod_allocate_triplet(1000, 1000, 1024, 0, CHOLMOD_REAL, &_cholmodCommon);
70  _L = 0;
71  _cholmodFactor = 0;
72  _solverInterface = 0;
73 
74  _permutedUpdateAsSparse = new CholmodExt;
75  }
76 
77  SparseOptimizerIncremental::~SparseOptimizerIncremental()
78  {
79  delete _permutedUpdateAsSparse;
80  _updateMat.clear(true);
81  delete _cholmodSparse;
82  if (_cholmodFactor) {
83  cholmod_free_factor(&_cholmodFactor, &_cholmodCommon);
84  _cholmodFactor = 0;
85  }
86  cholmod_free_triplet(&_permutedUpdate, &_cholmodCommon);
87  cholmod_finish(&_cholmodCommon);
88  }
89 
90  int SparseOptimizerIncremental::optimize(int iterations, bool online)
91  {
92  (void) iterations; // we only do one iteration anyhow
93  OptimizationAlgorithm* solver = _algorithm;
94  solver->init(online);
95 
96  int cjIterations=0;
97  bool ok=true;
98 
99  if (! online || batchStep) {
100  //cerr << "performing batch step" << endl;
101  if (! online) {
102  ok = _underlyingSolver->buildStructure();
103  if (! ok) {
104  cerr << __PRETTY_FUNCTION__ << ": Failure while building CCS structure" << endl;
105  return 0;
106  }
107  }
108 
109  // copy over the updated estimate as new linearization point
110  if (slamDimension == 3) {
111  for (size_t i = 0; i < indexMapping().size(); ++i) {
112  OnlineVertexSE2* v = static_cast<OnlineVertexSE2*>(indexMapping()[i]);
114  }
115  }
116  else if (slamDimension == 6) {
117  for (size_t i = 0; i < indexMapping().size(); ++i) {
118  OnlineVertexSE3* v= static_cast<OnlineVertexSE3*>(indexMapping()[i]);
120  }
121  }
122 
123  SparseOptimizer::computeActiveErrors();
124  //SparseOptimizer::linearizeSystem();
125  _underlyingSolver->buildSystem();
126 
127  // mark vertices to be sorted as last
128  int numBlocksRequired = _ivMap.size();
129  if (_cmember.size() < numBlocksRequired) {
130  _cmember.resize(2 * numBlocksRequired);
131  }
132  memset(_cmember.data(), 0, numBlocksRequired * sizeof(int));
133  if (_ivMap.size() > 100) {
134  for (size_t i = _ivMap.size() - 20; i < _ivMap.size(); ++i) {
135  const HyperGraph::EdgeSet& eset = _ivMap[i]->edges();
136  for (HyperGraph::EdgeSet::const_iterator it = eset.begin(); it != eset.end(); ++it) {
137  OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
138  OptimizableGraph::Vertex* v1 = static_cast<OptimizableGraph::Vertex*>(e->vertices()[0]);
139  OptimizableGraph::Vertex* v2 = static_cast<OptimizableGraph::Vertex*>(e->vertices()[1]);
140  if (v1->hessianIndex() >= 0)
141  _cmember(v1->hessianIndex()) = 1;
142  if (v2->hessianIndex() >= 0)
143  _cmember(v2->hessianIndex()) = 1;
144  }
145  }
146  //OptimizableGraph::Vertex* lastPose = _ivMap.back();
147  //_cmember(lastPose->hessianIndex()) = 2;
148  }
149 
150  ok = _underlyingSolver->solve();
151 
152  // get the current cholesky factor along with the permutation
153  _L = _solverInterface->L();
154  if (_perm.size() < (int)_L->n)
155  _perm.resize(2*_L->n);
156  int* p = (int*)_L->Perm;
157  for (size_t i = 0; i < _L->n; ++i)
158  _perm[p[i]] = i;
159 
160  }
161  else {
162  // update the b vector
163  for (HyperGraph::VertexSet::iterator it = _touchedVertices.begin(); it != _touchedVertices.end(); ++it) {
164  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it);
165  int iBase = v->colInHessian();
166  v->copyB(_underlyingSolver->b() + iBase);
167  }
168  _solverInterface->solve(_underlyingSolver->x(), _underlyingSolver->b());
169  }
170 
171  // print statistics for the non-zeros
172  //static ofstream debugNonZeros("non-zeros.txt");
173  //debugNonZeros << _solverInterface->nonZerosInL() << endl;
174 
175  update(_underlyingSolver->x());
176  ++cjIterations;
177 
178  if (verbose()){
179  computeActiveErrors();
180  cerr
181  << "nodes = " << vertices().size()
182  << "\t edges= " << _activeEdges.size()
183  << "\t chi2= " << FIXED(activeChi2())
184  << endl;
185  }
186 
187  if (vizWithGnuplot)
188  gnuplotVisualization();
189 
190  if (! ok)
191  return 0;
192  return 1;
193  }
194 
195  bool SparseOptimizerIncremental::updateInitialization(HyperGraph::VertexSet& vset, HyperGraph::EdgeSet& eset)
196  {
197  if (batchStep) {
198  return SparseOptimizerOnline::updateInitialization(vset, eset);
199  }
200 
201  for (HyperGraph::VertexSet::iterator it = vset.begin(); it != vset.end(); ++it) {
202  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it);
203  v->clearQuadraticForm(); // be sure that b is zero for this vertex
204  }
205 
206  // get the touched vertices
207  _touchedVertices.clear();
208  for (HyperGraph::EdgeSet::iterator it = eset.begin(); it != eset.end(); ++it) {
209  OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
210  OptimizableGraph::Vertex* v1 = static_cast<OptimizableGraph::Vertex*>(e->vertices()[0]);
211  OptimizableGraph::Vertex* v2 = static_cast<OptimizableGraph::Vertex*>(e->vertices()[1]);
212  if (! v1->fixed())
213  _touchedVertices.insert(v1);
214  if (! v2->fixed())
215  _touchedVertices.insert(v2);
216  }
217  //cerr << PVAR(_touchedVertices.size()) << endl;
218 
219  // updating the internal structures
220  std::vector<HyperGraph::Vertex*> newVertices;
221  newVertices.reserve(vset.size());
222  _activeVertices.reserve(_activeVertices.size() + vset.size());
223  _activeEdges.reserve(_activeEdges.size() + eset.size());
224  for (HyperGraph::EdgeSet::iterator it = eset.begin(); it != eset.end(); ++it)
225  _activeEdges.push_back(static_cast<OptimizableGraph::Edge*>(*it));
226  //cerr << "updating internal done." << endl;
227 
228  // update the index mapping
229  size_t next = _ivMap.size();
230  for (HyperGraph::VertexSet::iterator it = vset.begin(); it != vset.end(); ++it) {
232  if (! v->fixed()){
233  if (! v->marginalized()){
234  v->setHessianIndex(next);
235  _ivMap.push_back(v);
236  newVertices.push_back(v);
237  _activeVertices.push_back(v);
238  next++;
239  }
240  else // not supported right now
241  abort();
242  }
243  else {
244  v->setHessianIndex(-1);
245  }
246  }
247  //cerr << "updating index mapping done." << endl;
248 
249  // backup the tempindex and prepare sorting structure
250 #ifdef _MSC_VER
251  VertexBackup* backupIdx = new VertexBackup[_touchedVertices.size()];
252 #else
253  VertexBackup backupIdx[_touchedVertices.size()];
254 #endif
255  memset(backupIdx, 0, sizeof(VertexBackup) * _touchedVertices.size());
256  int idx = 0;
257  for (HyperGraph::VertexSet::iterator it = _touchedVertices.begin(); it != _touchedVertices.end(); ++it) {
258  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it);
259  backupIdx[idx].hessianIndex = v->hessianIndex();
260  backupIdx[idx].vertex = v;
261  backupIdx[idx].hessianData = v->hessianData();
262  ++idx;
263  }
264  sort(backupIdx, backupIdx + _touchedVertices.size()); // sort according to the hessianIndex which is the same order as used later by the optimizer
265  for (int i = 0; i < idx; ++i) {
266  backupIdx[i].vertex->setHessianIndex(i);
267  }
268  //cerr << "backup tempindex done." << endl;
269 
270  // building the structure of the update
271  _updateMat.clear(true); // get rid of the old matrix structure
272  _updateMat.rowBlockIndices().clear();
273  _updateMat.colBlockIndices().clear();
274  _updateMat.blockCols().clear();
275 
276  // placing the current stuff in _updateMat
277  MatrixXd* lastBlock = 0;
278  int sizePoses = 0;
279  for (int i = 0; i < idx; ++i) {
280  OptimizableGraph::Vertex* v = backupIdx[i].vertex;
281  int dim = v->dimension();
282  sizePoses+=dim;
283  _updateMat.rowBlockIndices().push_back(sizePoses);
284  _updateMat.colBlockIndices().push_back(sizePoses);
285  _updateMat.blockCols().push_back(SparseBlockMatrix<MatrixXd>::IntBlockMap());
286  int ind = v->hessianIndex();
287  //cerr << PVAR(ind) << endl;
288  if (ind >= 0) {
289  MatrixXd* m = _updateMat.block(ind, ind, true);
290  v->mapHessianMemory(m->data());
291  lastBlock = m;
292  }
293  }
294  lastBlock->diagonal().array() += 1e-6; // HACK to get Eigen value > 0
295 
296 
297  for (HyperGraph::EdgeSet::const_iterator it = eset.begin(); it != eset.end(); ++it) {
298  OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
301 
302  int ind1 = v1->hessianIndex();
303  if (ind1 == -1)
304  continue;
305  int ind2 = v2->hessianIndex();
306  if (ind2 == -1)
307  continue;
308  bool transposedBlock = ind1 > ind2;
309  if (transposedBlock) // make sure, we allocate the upper triangular block
310  swap(ind1, ind2);
311 
312  MatrixXd* m = _updateMat.block(ind1, ind2, true);
313  e->mapHessianMemory(m->data(), 0, 1, transposedBlock);
314  }
315 
316  // build the system into _updateMat
317  for (HyperGraph::EdgeSet::iterator it = eset.begin(); it != eset.end(); ++it) {
318  OptimizableGraph::Edge * e = static_cast<OptimizableGraph::Edge*>(*it);
319  e->computeError();
320  }
321  for (HyperGraph::EdgeSet::iterator it = eset.begin(); it != eset.end(); ++it) {
322  OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
323  e->linearizeOplus(jacobianWorkspace());
325  }
326 
327  // restore the original data for the vertex
328  for (int i = 0; i < idx; ++i) {
329  backupIdx[i].vertex->setHessianIndex(backupIdx[i].hessianIndex);
330  if (backupIdx[i].hessianData)
331  backupIdx[i].vertex->mapHessianMemory(backupIdx[i].hessianData);
332  }
333 
334  // update the structure of the real block matrix
335  bool solverStatus = _algorithm->updateStructure(newVertices, eset);
336 
337  bool updateStatus = computeCholeskyUpdate();
338  if (! updateStatus) {
339  cerr << "Error while computing update" << endl;
340  }
341 
342  cholmod_sparse* updateAsSparseFactor = cholmod_factor_to_sparse(_cholmodFactor, &_cholmodCommon);
343 
344  // convert CCS update by permuting back to the permutation of L
345  if (updateAsSparseFactor->nzmax > _permutedUpdate->nzmax) {
346  //cerr << "realloc _permutedUpdate" << endl;
347  cholmod_reallocate_triplet(updateAsSparseFactor->nzmax, _permutedUpdate, &_cholmodCommon);
348  }
349  _permutedUpdate->nnz = 0;
350  _permutedUpdate->nrow = _permutedUpdate->ncol = _L->n;
351  {
352  int* Ap = (int*)updateAsSparseFactor->p;
353  int* Ai = (int*)updateAsSparseFactor->i;
354  double* Ax = (double*)updateAsSparseFactor->x;
355  int* Bj = (int*)_permutedUpdate->j;
356  int* Bi = (int*)_permutedUpdate->i;
357  double* Bx = (double*)_permutedUpdate->x;
358  for (size_t c = 0; c < updateAsSparseFactor->ncol; ++c) {
359  const int& rbeg = Ap[c];
360  const int& rend = Ap[c+1];
361  int cc = c / slamDimension;
362  int coff = c % slamDimension;
363  const int& cbase = backupIdx[cc].vertex->colInHessian();
364  const int& ccol = _perm(cbase + coff);
365  for (int j = rbeg; j < rend; j++) {
366  const int& r = Ai[j];
367  const double& val = Ax[j];
368 
369  int rr = r / slamDimension;
370  int roff = r % slamDimension;
371  const int& rbase = backupIdx[rr].vertex->colInHessian();
372 
373  int row = _perm(rbase + roff);
374  int col = ccol;
375  if (col > row) // lower triangular entry
376  swap(col, row);
377  Bi[_permutedUpdate->nnz] = row;
378  Bj[_permutedUpdate->nnz] = col;
379  Bx[_permutedUpdate->nnz] = val;
380  ++_permutedUpdate->nnz;
381  }
382  }
383  }
384  cholmod_free_sparse(&updateAsSparseFactor, &_cholmodCommon);
385 #ifdef _MSC_VER
386  delete[] backupIdx;
387 #endif
388 
389 #if 0
390  cholmod_sparse* updatePermuted = cholmod_triplet_to_sparse(_permutedUpdate, _permutedUpdate->nnz, &_cholmodCommon);
391  //writeCCSMatrix("update-permuted.txt", updatePermuted->nrow, updatePermuted->ncol, (int*)updatePermuted->p, (int*)updatePermuted->i, (double*)updatePermuted->x, false);
392  _solverInterface->choleskyUpdate(updatePermuted);
393  cholmod_free_sparse(&updatePermuted, &_cholmodCommon);
394 #else
395  convertTripletUpdateToSparse();
396  _solverInterface->choleskyUpdate(_permutedUpdateAsSparse);
397 #endif
398 
399  return solverStatus;
400  }
401 
402  bool SparseOptimizerIncremental::computeCholeskyUpdate()
403  {
404  if (_cholmodFactor) {
405  cholmod_free_factor(&_cholmodFactor, &_cholmodCommon);
406  _cholmodFactor = 0;
407  }
408 
409  const SparseBlockMatrix<MatrixXd>& A = _updateMat;
410  size_t m = A.rows();
411  size_t n = A.cols();
412 
413  if (_cholmodSparse->columnsAllocated < n) {
414  //std::cerr << __PRETTY_FUNCTION__ << ": reallocating columns" << std::endl;
415  _cholmodSparse->columnsAllocated = _cholmodSparse->columnsAllocated == 0 ? n : 2 * n; // pre-allocate more space if re-allocating
416  delete[] (int*)_cholmodSparse->p;
417  _cholmodSparse->p = new int[_cholmodSparse->columnsAllocated+1];
418  }
419  size_t nzmax = A.nonZeros();
420  if (_cholmodSparse->nzmax < nzmax) {
421  //std::cerr << __PRETTY_FUNCTION__ << ": reallocating row + values" << std::endl;
422  _cholmodSparse->nzmax = _cholmodSparse->nzmax == 0 ? nzmax : 2 * nzmax; // pre-allocate more space if re-allocating
423  delete[] (double*)_cholmodSparse->x;
424  delete[] (int*)_cholmodSparse->i;
425  _cholmodSparse->i = new int[_cholmodSparse->nzmax];
426  _cholmodSparse->x = new double[_cholmodSparse->nzmax];
427  }
428  _cholmodSparse->ncol = n;
429  _cholmodSparse->nrow = m;
430 
431  A.fillCCS((int*)_cholmodSparse->p, (int*)_cholmodSparse->i, (double*)_cholmodSparse->x, true);
432  //writeCCSMatrix("updatesparse.txt", _cholmodSparse->nrow, _cholmodSparse->ncol, (int*)_cholmodSparse->p, (int*)_cholmodSparse->i, (double*)_cholmodSparse->x, true);
433 
434  _cholmodFactor = cholmod_analyze(_cholmodSparse, &_cholmodCommon);
435  cholmod_factorize(_cholmodSparse, _cholmodFactor, &_cholmodCommon);
436 
437 #if 0
438  int* p = (int*)_cholmodFactor->Perm;
439  for (int i = 0; i < (int)n; ++i)
440  if (i != p[i])
441  cerr << "wrong permutation" << i << " -> " << p[i] << endl;
442 #endif
443 
444  if (_cholmodCommon.status == CHOLMOD_NOT_POSDEF) {
445  //std::cerr << "Cholesky failure, writing debug.txt (Hessian loadable by Octave)" << std::endl;
446  //writeCCSMatrix("debug.txt", _cholmodSparse->nrow, _cholmodSparse->ncol, (int*)_cholmodSparse->p, (int*)_cholmodSparse->i, (double*)_cholmodSparse->x, true);
447  return false;
448  }
449 
450  // change to the specific format we need to have a pretty normal L
451  int change_status = cholmod_change_factor(CHOLMOD_REAL, 1, 0, 1, 1, _cholmodFactor, &_cholmodCommon);
452  if (! change_status) {
453  return false;
454  }
455 
456  return true;
457  }
458 
459  static OptimizationAlgorithm* createSolver(const std::string& solverName)
460  {
461  g2o::Solver* s = 0;
462 
463  if (solverName == "fix3_2_cholmod") {
464  ALLOC_CHOLMOD(s, 3, 2);
465  }
466  else if (solverName == "fix6_3_cholmod") {
467  ALLOC_CHOLMOD(s, 6, 3);
468  }
469 
471  return gaussNewton;
472  }
473 
474  bool SparseOptimizerIncremental::initSolver(int dimension, int batchEveryN)
475  {
476  //cerr << __PRETTY_FUNCTION__ << endl;
477  slamDimension = dimension;
478  if (dimension == 3) {
479  setAlgorithm(createSolver("fix3_2_cholmod"));
480  OptimizationAlgorithmGaussNewton* gaussNewton = dynamic_cast<OptimizationAlgorithmGaussNewton*>(solver());
481  assert(gaussNewton);
482  BlockSolver<BlockSolverTraits<3, 2> >* bs = dynamic_cast<BlockSolver<BlockSolverTraits<3, 2> >*>(gaussNewton->solver());
483  assert(bs && "Unable to get internal block solver");
485  bs->setAdditionalVectorSpace(300);
486  bs->setSchur(false);
487  _solverInterface = s;
488  _underlyingSolver = bs;
489  } else {
490  setAlgorithm(createSolver("fix6_3_cholmod"));
491  OptimizationAlgorithmGaussNewton* gaussNewton = dynamic_cast<OptimizationAlgorithmGaussNewton*>(solver());
492  assert(gaussNewton);
493  BlockSolver<BlockSolverTraits<6, 3> >* bs = dynamic_cast<BlockSolver<BlockSolverTraits<6, 3> >*>(gaussNewton->solver());
494  assert(bs && "Unable to get internal block solver");
496  bs->setAdditionalVectorSpace(600);
497  bs->setSchur(false);
498  _solverInterface = s;
499  _underlyingSolver = bs;
500  }
501  _solverInterface->cmember = &_cmember;
502  _solverInterface->batchEveryN = batchEveryN;
503  if (! solver()) {
504  cerr << "Error allocating solver. Allocating CHOLMOD solver failed!" << endl;
505  return false;
506  }
507  return true;
508  }
509 
510  void SparseOptimizerIncremental::convertTripletUpdateToSparse()
511  {
512  // re-allocate the memory
513  if (_tripletWorkspace.size() < (int)_permutedUpdate->ncol) {
514  _tripletWorkspace.resize(_permutedUpdate->ncol * 2);
515  }
516 
517  // reallocate num-zeros
518  if (_permutedUpdateAsSparse->nzmax < _permutedUpdate->nzmax) {
519  _permutedUpdateAsSparse->nzmax = _permutedUpdate->nzmax;
520  delete[] (int*)_permutedUpdateAsSparse->i;
521  delete[] (double*)_permutedUpdateAsSparse->x;
522  _permutedUpdateAsSparse->x = new double[_permutedUpdateAsSparse->nzmax];
523  _permutedUpdateAsSparse->i = new int[_permutedUpdateAsSparse->nzmax];
524  }
525 
526  if (_permutedUpdateAsSparse->columnsAllocated < _permutedUpdate->ncol) {
527  _permutedUpdateAsSparse->columnsAllocated = 2*_permutedUpdate->ncol;
528  delete[] (int*) _permutedUpdateAsSparse->p;
529  _permutedUpdateAsSparse->p = new int[_permutedUpdateAsSparse->columnsAllocated + 1];
530  }
531 
532  _permutedUpdateAsSparse->ncol = _permutedUpdate->ncol;
533  _permutedUpdateAsSparse->nrow = _permutedUpdate->nrow;
534 
535  int* w = _tripletWorkspace.data();
536  memset(w, 0, sizeof(int) * _permutedUpdate->ncol);
537 
538  int* Ti = (int*) _permutedUpdate->i;
539  int* Tj = (int*) _permutedUpdate->j;
540  double* Tx = (double*) _permutedUpdate->x;
541 
542  int* Cp = (int*) _permutedUpdateAsSparse->p;
543  int* Ci = (int*) _permutedUpdateAsSparse->i;
544  double* Cx = (double*) _permutedUpdateAsSparse->x;
545 
546  for (size_t k = 0; k < _permutedUpdate->nnz; ++k) /* column counts */
547  w[Tj [k]]++;
548 
549  /* column pointers */
550  int n = _permutedUpdate->ncol;
551  int nz = 0;
552  for (int i = 0 ; i < n ; i++) {
553  Cp[i] = nz;
554  nz += w[i];
555  w[i] = Cp[i];
556  }
557  Cp[n] = nz;
558  assert((size_t)nz == _permutedUpdate->nnz);
559 
560  int p;
561  for (size_t k = 0 ; k < _permutedUpdate->nnz ; ++k) {
562  p = w[Tj[k]]++;
563  Ci[p] = Ti[k] ; /* A(i,j) is the pth entry in C */
564  Cx[p] = Tx[k] ;
565  }
566 
567  }
568 
569 } // end namespace
#define __PRETTY_FUNCTION__
Definition: macros.h:89
void setHessianIndex(int ti)
set the temporary index of the vertex in the parameter blocks
virtual double * hessianData()=0
int cols() const
columns of the matrix
static OptimizationAlgorithm * createSolver(const std::string &solverName)
virtual int copyB(double *b_) const =0
virtual void setSchur(bool s)
Definition: block_solver.h:132
std::set< Vertex * > VertexSet
Definition: hyper_graph.h:136
int rows() const
rows of the matrix
virtual bool init(bool online=false)=0
void resize(int *blockPoseIndices, int numPoseBlocks, int *blockLandmarkIndices, int numLandmarkBlocks, int totalDim)
int hessianIndex() const
temporary index of this node in the parameter vector obtained from linearization
virtual void linearizeOplus(JacobianWorkspace &jacobianWorkspace)=0
size_t nonZeros() const
number of non-zero elements
Our extension of the CHOLMOD matrix struct.
Implementation of the Gauss Newton Algorithm.
Solver * solver()
return the underlying solver used to solve the linear system
void setAdditionalVectorSpace(size_t s)
Definition: solver.cpp:82
std::set< Edge * > EdgeSet
Definition: hyper_graph.h:135
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
const VertexContainer & vertices() const
Definition: hyper_graph.h:178
virtual void constructQuadraticForm()=0
LinearSolver< PoseMatrixType > * linearSolver() const
Definition: block_solver.h:134
int colInHessian() const
get the row of this vertex in the Hessian
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
virtual void mapHessianMemory(double *d)=0
std::map< int, SparseMatrixBlock * > IntBlockMap
virtual void clearQuadraticForm()=0
void setEstimate(const EstimateType &et)
set the estimate for the vertex also calls updateCache()
Definition: base_vertex.h:101
bool marginalized() const
true => this node is marginalized out during the optimization
A general case Vertex for optimization.
bool operator<(const HyperDijkstra::AdjacencyMapEntry &a, const HyperDijkstra::AdjacencyMapEntry &b)
bool fixed() const
true => this node is fixed during the optimization
VertexSE2::EstimateType updatedEstimate
Implementation of a solver operating on the blocks of the Hessian.
Definition: block_solver.h:96
Generic interface for a non-linear solver operating on a graph.
virtual void mapHessianMemory(double *d, int i, int j, bool rowMajor)=0
VertexSE3::EstimateType updatedEstimate
linear solver which allows to update the cholesky factor
Sparse matrix which uses blocks.
int fillCCS(int *Cp, int *Ci, double *Cx, bool upperTriangle=false) const
#define ALLOC_CHOLMOD(s, p, l)