g2o
optimizable_graph.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 "optimizable_graph.h"
28 
29 #include <cassert>
30 #include <iostream>
31 #include <iomanip>
32 #include <fstream>
33 #include <algorithm>
34 
35 #include <Eigen/Dense>
36 
37 #include "estimate_propagator.h"
38 #include "factory.h"
40 #include "hyper_graph_action.h"
41 #include "cache.h"
42 #include "robust_kernel.h"
43 
44 #include "g2o/stuff/macros.h"
45 #include "g2o/stuff/color_macros.h"
46 #include "g2o/stuff/string_tools.h"
47 #include "g2o/stuff/misc.h"
48 
49 namespace g2o {
50 
51  using namespace std;
52 
54  HyperGraph::Vertex(),
55  _graph(0), _userData(0), _hessianIndex(-1), _fixed(false), _marginalized(false),
56  _colInHessian(-1), _cacheContainer(0)
57  {
58  }
59 
61  if (! _cacheContainer)
62  _cacheContainer = new CacheContainer(this);
63  return _cacheContainer;
64  }
65 
66 
68  if (_cacheContainer){
71  }
72  }
73 
75  {
76  delete _cacheContainer;
77  delete _userData;
78  }
79 
81  {
82  return 0;
83  }
84 
86  {
87  bool ret = setEstimateDataImpl(v);
88  updateCache();
89  return ret;
90  }
91 
93  {
94  return false;
95  }
96 
98  {
99  return -1;
100  }
101 
103  {
104  bool ret = setMinimalEstimateDataImpl(v);
105  updateCache();
106  return ret;
107  }
108 
110  {
111  return false;
112  }
113 
115  {
116  return -1;
117  }
118 
119 
121  HyperGraph::Edge(),
122  _dimension(-1), _level(0), _robustKernel(0)
123  {
124  }
125 
127  {
128  delete _robustKernel;
129  }
130 
132  if (! _vertices.size())
133  return 0;
135  if (!v)
136  return 0;
137  return v->graph();
138  }
139 
141  if (! _vertices.size())
142  return 0;
144  if (!v)
145  return 0;
146  return v->graph();
147  }
148 
149  bool OptimizableGraph::Edge::setParameterId(int argNum, int paramId){
150  if ((int)_parameters.size()<=argNum)
151  return false;
152  if (argNum<0)
153  return false;
154  *_parameters[argNum] = 0;
155  _parameterIds[argNum] = paramId;
156  return true;
157  }
158 
160  if (!graph()) {
161  cerr << __PRETTY_FUNCTION__ << ": edge not registered with a graph" << endl;
162  return false;
163  }
164 
165  assert (_parameters.size() == _parameterIds.size());
166  //cerr << __PRETTY_FUNCTION__ << ": encountered " << _parameters.size() << " parameters" << endl;
167  for (size_t i=0; i<_parameters.size(); i++){
168  int index = _parameterIds[i];
169  *_parameters[i] = graph()->parameter(index);
170  if (typeid(**_parameters[i]).name()!=_parameterTypes[i]){
171  cerr << __PRETTY_FUNCTION__ << ": FATAL, parameter type mismatch - encountered " << typeid(**_parameters[i]).name() << "; should be " << _parameterTypes[i] << endl;
172  }
173  if (!*_parameters[i]) {
174  cerr << __PRETTY_FUNCTION__ << ": FATAL, *_parameters[i] == 0" << endl;
175  return false;
176  }
177  }
178  return true;
179  }
180 
182  {
183  if (_robustKernel)
184  delete _robustKernel;
185  _robustKernel = ptr;
186  }
187 
189  return true;
190  }
191 
193  {
194  return false;
195  }
196 
198  {
199  return false;
200  }
201 
203  {
204  return -1;
205  }
206 
208  return false;
209  }
210 
211 
213  {
214  // TODO
215  return 0;
216  }
217 
218 
220  {
221  _nextEdgeId = 0; _edge_has_id = false;
223  }
224 
226  {
227  clear();
228  clearParameters();
229  }
230 
232  {
233  if (v->id() <0){
234  cerr << __FUNCTION__ << ": FATAL, a vertex with (negative) ID " << v->id() << " cannot be inserted in the graph" << endl;
235  assert(0 && "Invalid vertex id");
236  return false;
237  }
238  Vertex* inserted = vertex(v->id());
239  if (inserted) {
240  cerr << __FUNCTION__ << ": FATAL, a vertex with ID " << v->id() << " has already been registered with this graph" << endl;
241  assert(0 && "Vertex with this ID already contained in the graph");
242  return false;
243  }
245  assert(ov && "Vertex does not inherit from OptimizableGraph::Vertex");
246  if (ov->_graph != 0 && ov->_graph != this) {
247  cerr << __FUNCTION__ << ": FATAL, vertex with ID " << v->id() << " has already registered with another graph " << ov->_graph << endl;
248  assert(0 && "Vertex already registered with another graph");
249  return false;
250  }
251  if (userData)
252  ov->setUserData(userData);
253  ov->_graph=this;
254  return HyperGraph::addVertex(v);
255  }
256 
258  {
259  OptimizableGraph::Edge* e = dynamic_cast<OptimizableGraph::Edge*>(e_);
260  assert(e && "Edge does not inherit from OptimizableGraph::Edge");
261  // std::cerr << "subclass of OptimizableGraph::Edge confirmed";
262  if (! e)
263  return false;
264  bool eresult = HyperGraph::addEdge(e);
265  if (! eresult)
266  return false;
267  // std::cerr << "called HyperGraph::addEdge" << std::endl;
268  e->_internalId = _nextEdgeId++;
269  if (e->numUndefinedVertices())
270  return true;
271  // std::cerr << "internalId set" << std::endl;
272  if (! e->resolveParameters()){
273  cerr << __FUNCTION__ << ": FATAL, cannot resolve parameters for edge " << e << endl;
274  return false;
275  }
276  // std::cerr << "parameters set" << std::endl;
277  if (! e->resolveCaches()){
278  cerr << __FUNCTION__ << ": FATAL, cannot resolve caches for edge " << e << endl;
279  return false;
280  }
281  // std::cerr << "updating jacobian size" << std::endl;
283 
284  // std::cerr << "about to return true" << std::endl;
285 
286  return true;
287  }
288 
290  if (! HyperGraph::setEdgeVertex(e,pos,v)){
291  return false;
292  }
293  if (!e->numUndefinedVertices()){
294 #ifndef NDEBUG
295  OptimizableGraph::Edge* ee = dynamic_cast<OptimizableGraph::Edge*>(e);
296  assert(ee && "Edge is not a OptimizableGraph::Edge");
297 #else
298  OptimizableGraph::Edge* ee = static_cast<OptimizableGraph::Edge*>(e);
299 #endif
300  if (! ee->resolveParameters()){
301  cerr << __FUNCTION__ << ": FATAL, cannot resolve parameters for edge " << e << endl;
302  return false;
303  }
304  if (! ee->resolveCaches()){
305  cerr << __FUNCTION__ << ": FATAL, cannot resolve caches for edge " << e << endl;
306  return false;
307  }
309  }
310  return true;
311  }
312 
313  int OptimizableGraph::optimize(int /*iterations*/, bool /*online*/) {return 0;}
314 
316 {
317  double chi = 0.0;
318  for (OptimizableGraph::EdgeSet::const_iterator it = this->edges().begin(); it != this->edges().end(); ++it) {
319  const OptimizableGraph::Edge* e = static_cast<const OptimizableGraph::Edge*>(*it);
320  chi += e->chi2();
321  }
322  return chi;
323 }
324 
326 {
327  for (OptimizableGraph::VertexIDMap::iterator it=_vertices.begin(); it!=_vertices.end(); ++it) {
328  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(it->second);
329  v->push();
330  }
331 }
332 
334 {
335  for (OptimizableGraph::VertexIDMap::iterator it=_vertices.begin(); it!=_vertices.end(); ++it) {
336  OptimizableGraph::Vertex* v= static_cast<OptimizableGraph::Vertex*>(it->second);
337  v->pop();
338  }
339 }
340 
342 {
343  for (OptimizableGraph::VertexIDMap::iterator it=_vertices.begin(); it!=_vertices.end(); ++it) {
344  OptimizableGraph::Vertex* v= static_cast<OptimizableGraph::Vertex*>(it->second);
345  v->discardTop();
346  }
347 }
348 
350 {
351  for (HyperGraph::VertexSet::iterator it=vset.begin(); it!=vset.end(); ++it) {
352  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it);
353  v->push();
354  }
355 }
356 
358 {
359  for (HyperGraph::VertexSet::iterator it=vset.begin(); it!=vset.end(); ++it) {
360  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it);
361  v->pop();
362  }
363 }
364 
366 {
367  for (HyperGraph::VertexSet::iterator it=vset.begin(); it!=vset.end(); ++it) {
368  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it);
369  v->discardTop();
370  }
371 }
372 
374 {
375  for (HyperGraph::VertexSet::iterator it=vset.begin(); it!=vset.end(); ++it) {
376  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it);
377  v->setFixed(fixed);
378  }
379 }
380 
381 
382 bool OptimizableGraph::load(istream& is, bool createEdges)
383 {
384  // scna for the paramers in the whole file
385  if (!_parameters.read(is,&_renamedTypesLookup))
386  return false;
387 #ifndef NDEBUG
388  cerr << "Loaded " << _parameters.size() << " parameters" << endl;
389 #endif
390  is.clear();
391  is.seekg(ios_base::beg);
392  set<string> warnedUnknownTypes;
393  stringstream currentLine;
394  string token;
395 
396  Factory* factory = Factory::instance();
397  HyperGraph::GraphElemBitset elemBitset;
398  elemBitset[HyperGraph::HGET_PARAMETER] = 1;
399  elemBitset.flip();
400 
401  HyperGraph::DataContainer* previousDataContainer = 0;
402  Data* previousData = 0;
403 
404  int lineNumber = 0;
405  while (1) {
406  int bytesRead = readLine(is, currentLine);
407  lineNumber ++;
408  if (bytesRead == -1)
409  break;
410  currentLine >> token;
411  //cerr << "Token=" << token << endl;
412  if (bytesRead == 0 || token.size() == 0 || token[0] == '#')
413  continue;
414 
415  // handle commands encoded in the file
416  bool handledCommand = false;
417 
418  if (token == "FIX") {
419  handledCommand = true;
420  int id;
421  while (currentLine >> id) {
423  if (v) {
424 # ifndef NDEBUG
425  cerr << "Fixing vertex " << v->id() << endl;
426 # endif
427  v->setFixed(true);
428  } else {
429  cerr << "Warning: Unable to fix vertex with id " << id << ". Not found in the graph." << endl;
430  }
431  }
432  }
433 
434  if (handledCommand)
435  continue;
436 
437  // do the mapping to an internal type if it matches
438  if (_renamedTypesLookup.size() > 0) {
439  map<string, string>::const_iterator foundIt = _renamedTypesLookup.find(token);
440  if (foundIt != _renamedTypesLookup.end()) {
441  token = foundIt->second;
442  }
443  }
444 
445  if (! factory->knowsTag(token)) {
446  if (warnedUnknownTypes.count(token) != 1) {
447  warnedUnknownTypes.insert(token);
448  cerr << CL_RED(__PRETTY_FUNCTION__ << " unknown type: " << token) << endl;
449  }
450  continue;
451  }
452 
453  HyperGraph::HyperGraphElement* element = factory->construct(token, elemBitset);
454  if (dynamic_cast<Vertex*>(element)) { // it's a vertex type
455  //cerr << "it is a vertex" << endl;
456  previousData = 0;
457  Vertex* v = static_cast<Vertex*>(element);
458  int id;
459  currentLine >> id;
460  bool r = v->read(currentLine);
461  if (! r)
462  cerr << __PRETTY_FUNCTION__ << ": Error reading vertex " << token << " " << id << endl;
463  v->setId(id);
464  if (!addVertex(v)) {
465  cerr << __PRETTY_FUNCTION__ << ": Failure adding Vertex, " << token << " " << id << endl;
466  delete v;
467  } else {
468  previousDataContainer = v;
469  }
470  }
471  else if (dynamic_cast<Edge*>(element)) {
472  //cerr << "it is an edge" << endl;
473  previousData = 0;
474  Edge* e = static_cast<Edge*>(element);
475  int numV = e->vertices().size();
476  if (_edge_has_id){
477  int id;
478  currentLine >> id;
479  e->setId(id);
480  }
481  //cerr << PVAR(token) << " " << PVAR(numV) << endl;
482  if (numV == 2) { // it's a pairwise / binary edge type which we handle in a special way
483  int id1, id2;
484  currentLine >> id1 >> id2;
485  Vertex* from = vertex(id1);
486  Vertex* to = vertex(id2);
487  int doInit=0;
488 
489  if (createEdges){
490  if (! from && id1 >=0) {
491  from=e->createVertex(0);
492  from->setId(id1);
493  addVertex(from);
494  doInit=2;
495  }
496  if (! to && id2 >=0) {
497  to=e->createVertex(1);
498  to->setId(id2);
499  addVertex(to);
500  doInit=1;
501  }
502  if (id1<0 || id2<0)
503  doInit = 0;
504  } else {
505  if ( (!from && id1>=0) ){
506  cerr << __PRETTY_FUNCTION__ << ": Unable to find vertex for edge " << token << " " << id1 << " <-> " << id2 << endl;
507  delete e;
508  e=0;
509  }
510  if (! to && id2>=0 ){
511  cerr << __PRETTY_FUNCTION__ << ": Unable to find vertex for edge " << token << " " << id1 << " <-> " << id2 << endl;
512  delete e;
513  e=0;
514  }
515  }
516  if (e){
517  e->setVertex(0, from);
518  e->setVertex(1, to);
519  e->read(currentLine);
520  if (!addEdge(e)) {
521  cerr << __PRETTY_FUNCTION__ << ": Unable to add edge " << token << " " << id1 << " <-> " << id2 << endl;
522  delete e;
523  } else {
524  switch (doInit){
525  case 1:
526  {
527  HyperGraph::VertexSet fromSet;
528  fromSet.insert(from);
529  e->initialEstimate(fromSet, to);
530  break;
531  }
532  case 2:
533  {
534  HyperGraph::VertexSet toSet;
535  toSet.insert(to);
536  e->initialEstimate(toSet, from);
537  break;
538  }
539  default:;
540  }
541  }
542  }
543  }
544  else { // numV != 2
545  vector<int> ids;
546  if(numV!=0){
547  ids.resize(numV);
548  for (int l = 0; l < numV; ++l)
549  currentLine >> ids[l];
550  }
551  else{
552  string buff;
553  currentLine >> buff;
554  while(buff != "||"){
555  ids.push_back(atoi(buff.c_str()));
556  currentLine >> buff;
557  }
558  numV = ids.size();
559  e->resize(numV);
560  }
561  bool vertsOkay = true;
562  for (int l = 0; l < numV; ++l) {
563  int vertexId=ids[l];
564  HyperGraph::Vertex* v=0;
565  if (vertexId != HyperGraph::UnassignedId){
566  v = vertex(vertexId);
567  e->setVertex(l,v);
568  if (!v) {
569  vertsOkay = false;
570  break;
571  }
572  }
573  }
574  if (! vertsOkay) {
575  cerr << __PRETTY_FUNCTION__ << ": Unable to find vertices for edge " << token;
576  for (int l = 0; l < numV; ++l) {
577  if (l > 0)
578  cerr << " <->";
579  cerr << " " << ids[l];
580  }
581  delete e;
582  } else {
583  bool r = e->read(currentLine);
584  if (!r || !addEdge(e)) {
585  cerr << __PRETTY_FUNCTION__ << ": Unable to add edge " << token;
586  for (int l = 0; l < numV; ++l) {
587  if (l > 0)
588  cerr << " <->";
589  cerr << " " << ids[l];
590  }
591  delete e;
592  e=0;
593  }
594  }
595  }
596  previousDataContainer = e;
597  } else if (dynamic_cast<Data*>(element)) { // reading in the data packet for the vertex
598  //cerr << "read data packet " << token << " vertex " << previousVertex->id() << endl;
599  Data* d = static_cast<Data*>(element);
600  bool r = d->read(currentLine);
601  if (! r) {
602  cerr << __PRETTY_FUNCTION__ << ": Error reading data " << token << " at line " << lineNumber << endl;
603  delete d;
604  previousData = 0;
605  } else if (previousData){
606  //cerr << "chaining" << endl;
607  previousData->setNext(d);
608  d->setDataContainer(previousData->dataContainer());
609  previousData = d;
610  //cerr << "done" << endl;
611  } else if (previousDataContainer){
612  //cerr << "embedding in vertex" << endl;
613  previousDataContainer->setUserData(d);
614  d->setDataContainer(previousDataContainer);
615  previousData = d;
616  previousDataContainer = 0;
617  //cerr << "done" << endl;
618  } else {
619  cerr << __PRETTY_FUNCTION__ << ": got data element, but no data container available" << endl;
620  delete d;
621  previousData = 0;
622  }
623  }
624  } // while read line
625 
626  return true;
627 }
628 
629 bool OptimizableGraph::load(const char* filename, bool createEdges)
630 {
631  ifstream ifs(filename);
632  if (!ifs) {
633  cerr << __PRETTY_FUNCTION__ << " unable to open file " << filename << endl;
634  return false;
635  }
636  return load(ifs, createEdges);
637 }
638 
639 bool OptimizableGraph::save(const char* filename, int level) const
640 {
641  ofstream ofs(filename);
642  if (!ofs)
643  return false;
644  return save(ofs, level);
645 }
646 
647 bool OptimizableGraph::save(ostream& os, int level) const
648 {
649  if (! _parameters.write(os))
650  return false;
651  set<Vertex*, VertexIDCompare> verticesToSave;
652  for (HyperGraph::EdgeSet::const_iterator it = edges().begin(); it != edges().end(); ++it) {
653  OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
654  if (e->level() == level) {
655  for (vector<HyperGraph::Vertex*>::const_iterator it = e->vertices().begin(); it != e->vertices().end(); ++it) {
656  if (*it)
657  verticesToSave.insert(static_cast<OptimizableGraph::Vertex*>(*it));
658  }
659  }
660  }
661 
662  for (set<Vertex*, VertexIDCompare>::const_iterator it = verticesToSave.begin(); it != verticesToSave.end(); ++it){
663  OptimizableGraph::Vertex* v = *it;
664  saveVertex(os, v);
665  }
666 
667  EdgeContainer edgesToSave;
668  for (HyperGraph::EdgeSet::const_iterator it = edges().begin(); it != edges().end(); ++it) {
669  const OptimizableGraph::Edge* e = dynamic_cast<const OptimizableGraph::Edge*>(*it);
670  if (e->level() == level)
671  edgesToSave.push_back(const_cast<Edge*>(e));
672  }
673  sort(edgesToSave.begin(), edgesToSave.end(), EdgeIDCompare());
674 
675  for (EdgeContainer::const_iterator it = edgesToSave.begin(); it != edgesToSave.end(); ++it) {
676  OptimizableGraph::Edge* e = *it;
677  saveEdge(os, e);
678  }
679 
680  return os.good();
681 }
682 
683 
684 bool OptimizableGraph::saveSubset(ostream& os, HyperGraph::VertexSet& vset, int level)
685 {
686  if (! _parameters.write(os))
687  return false;
688 
689  for (HyperGraph::VertexSet::const_iterator it=vset.begin(); it!=vset.end(); it++){
690  OptimizableGraph::Vertex* v = dynamic_cast<OptimizableGraph::Vertex*>(*it);
691  saveVertex(os, v);
692  }
693  for (HyperGraph::EdgeSet::const_iterator it = edges().begin(); it != edges().end(); ++it) {
694  OptimizableGraph::Edge* e = dynamic_cast< OptimizableGraph::Edge*>(*it);
695  if (e->level() != level)
696  continue;
697 
698  bool verticesInEdge = true;
699  for (vector<HyperGraph::Vertex*>::const_iterator it = e->vertices().begin(); it != e->vertices().end(); ++it) {
700  if (vset.find(*it) == vset.end()) {
701  verticesInEdge = false;
702  break;
703  }
704  }
705  if (! verticesInEdge)
706  continue;
707 
708  saveEdge(os, e);
709  }
710 
711  return os.good();
712 }
713 
714 bool OptimizableGraph::saveSubset(ostream& os, HyperGraph::EdgeSet& eset)
715 {
716  if (!_parameters.write(os))
717  return false;
718  std::set<OptimizableGraph::Vertex*> vset;
719  for (HyperGraph::EdgeSet::const_iterator it = eset.begin(); it != eset.end(); ++it) {
720  HyperGraph::Edge* e = *it;
721  for (vector<HyperGraph::Vertex*>::const_iterator it = e->vertices().begin(); it != e->vertices().end(); ++it) {
722  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it);
723  if (v)
724  vset.insert(v);
725  }
726  }
727 
728  for (std::set<OptimizableGraph::Vertex*>::const_iterator it=vset.begin(); it!=vset.end(); ++it){
729  OptimizableGraph::Vertex* v = dynamic_cast<OptimizableGraph::Vertex*>(*it);
730  saveVertex(os, v);
731  }
732 
733  for (HyperGraph::EdgeSet::const_iterator it = eset.begin(); it != eset.end(); ++it) {
734  OptimizableGraph::Edge* e = dynamic_cast< OptimizableGraph::Edge*>(*it);
735  saveEdge(os, e);
736  }
737 
738  return os.good();
739 }
740 
742  for (HyperGraph::VertexIDMap::iterator it=g->vertices().begin(); it!=g->vertices().end(); ++it){
744  if (vertex(v->id()))
745  continue;
747  v2->edges().clear();
748  v2->setHessianIndex(-1);
749  addVertex(v2);
750  }
751  for (HyperGraph::EdgeSet::iterator it=g->edges().begin(); it!=g->edges().end(); ++it){
753  OptimizableGraph::Edge* en = e->clone();
754  en->resize(e->vertices().size());
755  int cnt = 0;
756  for (vector<HyperGraph::Vertex*>::const_iterator it = e->vertices().begin(); it != e->vertices().end(); ++it) {
758  assert(v);
759  en->setVertex(cnt++, v);
760  }
761  addEdge(en);
762  }
763 }
764 
766  int maxDim=0;
767  for (HyperGraph::VertexIDMap::const_iterator it=vertices().begin(); it!=vertices().end(); ++it){
768  const OptimizableGraph::Vertex* v= static_cast< const OptimizableGraph::Vertex*>(it->second);
769  maxDim = (std::max)(maxDim, v->dimension());
770  }
771  return maxDim;
772 }
773 
775 {
776  Factory* factory = Factory::instance();
777  vector<string> typesMap = strSplit(types, ",");
778  for (size_t i = 0; i < typesMap.size(); ++i) {
779  vector<string> m = strSplit(typesMap[i], "=");
780  if (m.size() != 2) {
781  cerr << __PRETTY_FUNCTION__ << ": unable to extract type map from " << typesMap[i] << endl;
782  continue;
783  }
784  string typeInFile = trim(m[0]);
785  string loadedType = trim(m[1]);
786  if (! factory->knowsTag(loadedType)) {
787  cerr << __PRETTY_FUNCTION__ << ": unknown type " << loadedType << endl;
788  continue;
789  }
790 
791  _renamedTypesLookup[typeInFile] = loadedType;
792  }
793 
794  cerr << "# load look up table" << endl;
795  for (std::map<std::string, std::string>::const_iterator it = _renamedTypesLookup.begin(); it != _renamedTypesLookup.end(); ++it) {
796  cerr << "#\t" << it->first << " -> " << it->second << endl;
797  }
798 }
799 
800 bool OptimizableGraph::isSolverSuitable(const OptimizationAlgorithmProperty& solverProperty, const std::set<int>& vertDims_) const
801 {
802  std::set<int> auxDims;
803  if (vertDims_.size() == 0) {
804  auxDims = dimensions();
805  }
806  const set<int>& vertDims = vertDims_.size() == 0 ? auxDims : vertDims_;
807  bool suitableSolver = true;
808  if (vertDims.size() == 2) {
809  if (solverProperty.requiresMarginalize) {
810  suitableSolver = vertDims.count(solverProperty.poseDim) == 1 && vertDims.count(solverProperty.landmarkDim) == 1;
811  }
812  else {
813  suitableSolver = solverProperty.poseDim == -1;
814  }
815  } else if (vertDims.size() == 1) {
816  suitableSolver = vertDims.count(solverProperty.poseDim) == 1 || solverProperty.poseDim == -1;
817  } else {
818  suitableSolver = solverProperty.poseDim == -1 && !solverProperty.requiresMarginalize;
819  }
820  return suitableSolver;
821 }
822 
823 std::set<int> OptimizableGraph::dimensions() const
824 {
825  std::set<int> auxDims;
826  for (VertexIDMap::const_iterator it = vertices().begin(); it != vertices().end(); ++it) {
827  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(it->second);
828  auxDims.insert(v->dimension());
829  }
830  return auxDims;
831 }
832 
834 {
836  if (actions.size() > 0) {
838  for (HyperGraphActionSet::iterator it = actions.begin(); it != actions.end(); ++it) {
839  (*(*it))(this, &params);
840  }
841  }
842 }
843 
845 {
847  if (actions.size() > 0) {
849  for (HyperGraphActionSet::iterator it = actions.begin(); it != actions.end(); ++it) {
850  (*(*it))(this, &params);
851  }
852  }
853 }
854 
856 {
857  std::pair<HyperGraphActionSet::iterator, bool> insertResult = _graphActions[AT_POSTITERATION].insert(action);
858  return insertResult.second;
859 }
860 
862 {
863  std::pair<HyperGraphActionSet::iterator, bool> insertResult = _graphActions[AT_PREITERATION].insert(action);
864  return insertResult.second;
865 }
866 
868 {
869  return _graphActions[AT_PREITERATION].erase(action) > 0;
870 }
871 
873 {
874  return _graphActions[AT_POSTITERATION].erase(action) > 0;
875 }
876 
877 bool OptimizableGraph::saveUserData(std::ostream& os, HyperGraph::Data* d) const {
878  Factory* factory = Factory::instance();
879  while (d) { // write the data packet for the vertex
880  string tag = factory->tag(d);
881  if (tag.size() > 0) {
882  os << tag << " ";
883  d->write(os);
884  os << endl;
885  }
886  d=d->next();
887  }
888  return os.good();
889 }
890 
892 {
893  Factory* factory = Factory::instance();
894  string tag = factory->tag(v);
895  if (tag.size() > 0) {
896  os << tag << " " << v->id() << " ";
897  v->write(os);
898  os << endl;
899  saveUserData(os, v->userData());
900  if (v->fixed()) {
901  os << "FIX " << v->id() << endl;
902  }
903  return os.good();
904  }
905  return false;
906 }
907 
908 bool OptimizableGraph::saveParameter(std::ostream& os, Parameter* p) const
909 {
910  Factory* factory = Factory::instance();
911  string tag = factory->tag(p);
912  if (tag.size() > 0) {
913  os << tag << " " << p->id() << " ";
914  p->write(os);
915  os << endl;
916  }
917  return os.good();
918 }
919 
920 bool OptimizableGraph::saveEdge(std::ostream& os, OptimizableGraph::Edge* e) const
921 {
922  Factory* factory = Factory::instance();
923  string tag = factory->tag(e);
924  if (tag.size() > 0) {
925  os << tag << " ";
926  if (_edge_has_id)
927  os << e->id() << " ";
928  for (vector<HyperGraph::Vertex*>::const_iterator it = e->vertices().begin(); it != e->vertices().end(); ++it) {
929  int vertexId = (*it) ? (*it)->id() : HyperGraph::UnassignedId;
930  os << vertexId << " ";
931  }
932  e->write(os);
933  os << endl;
934  saveUserData(os, e->userData());
935  return os.good();
936  }
937  return false;
938 }
939 
941 {
943  _parameters.clear();
944 }
945 
947 {
948  bool allEdgeOk = true;
949  Eigen::SelfAdjointEigenSolver<MatrixXD> eigenSolver;
950  for (OptimizableGraph::EdgeSet::const_iterator it = edges().begin(); it != edges().end(); ++it) {
951  OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
952  MatrixXD::MapType information(e->informationData(), e->dimension(), e->dimension());
953  // test on symmetry
954  bool isSymmetric = information.transpose() == information;
955  bool okay = isSymmetric;
956  if (isSymmetric) {
957  // compute the eigenvalues
958  eigenSolver.compute(information, Eigen::EigenvaluesOnly);
959  bool isSPD = eigenSolver.eigenvalues()(0) >= 0.;
960  okay = okay && isSPD;
961  }
962  allEdgeOk = allEdgeOk && okay;
963  if (! okay) {
964  if (verbose) {
965  if (! isSymmetric)
966  cerr << "Information Matrix for an edge is not symmetric:";
967  else
968  cerr << "Information Matrix for an edge is not SPD:";
969  for (size_t i = 0; i < e->vertices().size(); ++i)
970  cerr << " " << e->vertex(i)->id();
971  if (isSymmetric)
972  cerr << "\teigenvalues: " << eigenSolver.eigenvalues().transpose();
973  cerr << endl;
974  }
975  }
976  }
977  return allEdgeOk;
978 }
979 
981 {
982 # if (defined G2O_OPENMP) && EIGEN_VERSION_AT_LEAST(3,1,0)
983  Eigen::initParallel();
984 # endif
985  return true;
986 }
987 
988 } // end namespace
989 
stuff to open files and other unsorted components ProjectiveCamera types
const Data * next() const
Definition: hyper_graph.h:106
virtual bool setEdgeVertex(HyperGraph::Edge *e, int pos, HyperGraph::Vertex *v)
virtual bool write(std::ostream &os) const =0
write the vertex to a stream
virtual bool write(std::ostream &os) const =0
write the data to a stream
int id() const
returns the id
Definition: hyper_graph.h:148
const Vertex * vertex(size_t i) const
Definition: hyper_graph.h:186
#define __PRETTY_FUNCTION__
Definition: macros.h:89
void setHessianIndex(int ti)
set the temporary index of the vertex in the parameter blocks
const OptimizableGraph * graph() const
static Factory * instance()
return the instance
Definition: factory.cpp:61
virtual bool getEstimateData(double *estimate) const
virtual int optimize(int iterations, bool online=false)
some general case utility functions
data packet for a vertex. Extend this class to store in the vertices the potential additional informa...
Definition: hyper_graph.h:97
bool saveParameter(std::ostream &os, Parameter *v) const
std::vector< std::string > _parameterTypes
const Data * userData() const
the user data associated with this vertex
Definition: hyper_graph.h:126
int dimension() const
returns the dimensions of the error function
describe the properties of a solver
virtual bool write(std::ostream &os) const =0
write the data to a stream
virtual void discardTop()=0
pop the last element from the stack, without restoring the current estimate
virtual Vertex * createVertex(int)
bool removePreIterationAction(HyperGraphAction *action)
remove an action that should no longer be execured before each iteration
std::bitset< HyperGraph::HGET_NUM_ELEMS > GraphElemBitset
Definition: hyper_graph.h:74
bool saveEdge(std::ostream &os, Edge *e) const
virtual void clearParameters()
std::set< Vertex * > VertexSet
Definition: hyper_graph.h:136
HyperGraph::HyperGraphElement * construct(const std::string &tag) const
Definition: factory.cpp:147
virtual double chi2() const =0
computes the chi2 based on the cached error value, only valid after computeError has been called...
bool removePostIterationAction(HyperGraphAction *action)
remove an action that should no longer be execured after each iteration
virtual bool read(std::istream &is)=0
read the vertex from a stream, i.e., the internal state of the vertex
#define CL_RED(s)
Definition: color_macros.h:46
virtual void pop()
pop (restore) the estimate of all variables from the stack
SlamParser::Parser::token token
virtual void push()
push the estimate of all variables onto a stack
int landmarkDim
dimension of the landmar vertices (-1 if variable)
int level() const
returns the level of the edge
bool addPostIterationAction(HyperGraphAction *action)
add an action to be executed after each iteration
int maxDimension() const
return the maximum dimension of all vertices in the graph
virtual int measurementDimension() const
static bool initMultiThreading()
void setRobustKernel(RobustKernel *ptr)
virtual bool setMinimalEstimateDataImpl(const double *)
bool saveUserData(std::ostream &os, HyperGraph::Data *v) const
virtual void postIteration(int)
called at the end of an iteration (argument is the number of the iteration)
void setVertex(size_t i, Vertex *v)
Definition: hyper_graph.h:194
virtual bool addEdge(Edge *e)
const VertexIDMap & vertices() const
Definition: hyper_graph.h:225
virtual bool read(std::istream &is)=0
read the data from a stream
base for all robust cost functions
Definition: robust_kernel.h:48
virtual const double * informationData() const =0
returns the memory of the information matrix, usable for example with a Eigen::Map<MatrixXD> ...
void setUpdateNeeded(bool needUpdate=true)
Definition: cache.cpp:172
std::vector< Parameter ** > _parameters
std::string trim(const std::string &s)
virtual bool setEdgeVertex(Edge *e, int pos, Vertex *v)
virtual void setId(int id)
sets the id of the node in the graph be sure that the graph keeps consistent after changing the id ...
virtual bool setEstimateDataImpl(const double *)
std::vector< std::string > strSplit(const std::string &str, const std::string &delimiters)
std::vector< OptimizableGraph::Edge * > EdgeContainer
vector container for edges
std::set< Edge * > EdgeSet
Definition: hyper_graph.h:135
int dimension() const
dimension of the estimated state belonging to this node
int numUndefinedVertices() const
Definition: hyper_graph.cpp:59
bool setParameterId(int argNum, int paramId)
const VertexContainer & vertices() const
Definition: hyper_graph.h:178
double chi2() const
returns the chi2 of the current configuration
const std::string & tag(const HyperGraph::HyperGraphElement *v) const
return the TAG given a vertex
Definition: factory.cpp:157
const EdgeSet & edges() const
returns the set of hyper-edges that are leaving/entering in this vertex
Definition: hyper_graph.h:151
virtual bool save(std::ostream &os, int level=0) const
save the graph to a stream. Again uses the Factory system.
void setDataContainer(DataContainer *dataContainer_)
Definition: hyper_graph.h:111
bool isSolverSuitable(const OptimizationAlgorithmProperty &solverProperty, const std::set< int > &vertDims=std::set< int >()) const
virtual int estimateDimension() const
virtual void initialEstimate(const OptimizableGraph::VertexSet &from, OptimizableGraph::Vertex *to)=0
const EdgeSet & edges() const
Definition: hyper_graph.h:230
bool saveSubset(std::ostream &os, HyperGraph::VertexSet &vset, int level=0)
save a subgraph to a stream. Again uses the Factory system.
bool setMinimalEstimateData(const double *estimate)
void updateSize(const HyperGraph::Edge *e)
virtual bool setMeasurementData(const double *m)
std::vector< int > _parameterIds
create vertices and edges based on TAGs in, for example, a file
Definition: factory.h:49
int id() const
Definition: parameter.h:45
virtual void push()=0
backup the position of the vertex to a stack
int readLine(std::istream &is, std::stringstream &currentLine)
virtual void clear()
clears the graph and empties all structures.
virtual void pop()=0
restore the position of the vertex by retrieving the position from the stack
virtual int minimalEstimateDimension() const
virtual bool getMinimalEstimateData(double *estimate) const
bool knowsTag(const std::string &tag, int *elementType=0) const
Definition: factory.cpp:173
std::map< std::string, std::string > _renamedTypesLookup
Protocol The SLAM executable accepts actions
Definition: protocol.txt:3
DataContainer * dataContainer()
Definition: hyper_graph.h:109
order edges based on the internal ID, which is assigned to the edge in addEdge()
A general case Vertex for optimization.
abstract Vertex, your types must derive from that one
Definition: hyper_graph.h:142
OptimizableGraph()
empty constructor
void setRenamedTypesFromString(const std::string &types)
void addGraph(OptimizableGraph *g)
adds all edges and vertices of the graph g to this graph.
virtual bool addVertex(Vertex *v)
Definition: hyper_graph.cpp:94
void setNext(Data *next_)
Definition: hyper_graph.h:108
virtual void resize(size_t size)
Definition: hyper_graph.cpp:68
virtual bool load(std::istream &is, bool createEdges=true)
load the graph from a stream. Uses the Factory singleton for creating the vertices and edges...
bool setEstimateData(const double *estimate)
Parameter * parameter(int id)
JacobianWorkspace _jacobianWorkspace
virtual void setFixed(HyperGraph::VertexSet &vset, bool fixed)
fixes/releases a set of vertices
bool saveVertex(std::ostream &os, Vertex *v) const
virtual void preIteration(int)
called at the beginning of an iteration (argument is the number of the iteration) ...
bool fixed() const
true => this node is fixed during the optimization
HGET_PARAMETER
Definition: hyper_graph.h:63
std::set< HyperGraphAction * > HyperGraphActionSet
virtual Vertex * clone() const
returns a deep copy of the current vertex
virtual bool getMeasurementData(double *m) const
virtual bool write(std::ostream &os) const =0
write the vertex to a stream
bool requiresMarginalize
whether the solver requires marginalization of landmarks
virtual void discardTop()
discard the last backup of the estimate for all variables by removing it from the stack ...
void setFixed(bool fixed)
true => this node should be considered fixed during the optimization
static const int UnassignedId
Definition: hyper_graph.h:71
Container class that implements an interface for adding/removing Data elements in a linked list...
Definition: hyper_graph.h:121
bool verifyInformationMatrices(bool verbose=false) const
virtual bool read(std::istream &is)=0
read the vertex from a stream, i.e., the internal state of the vertex
std::vector< HyperGraphActionSet > _graphActions
virtual bool addEdge(HyperGraph::Edge *e)
virtual bool addVertex(HyperGraph::Vertex *v, Data *userData)
virtual Edge * clone() const
std::set< int > dimensions() const
int poseDim
dimension of the pose vertices (-1 if variable)
bool addPreIterationAction(HyperGraphAction *action)
add an action to be executed before each iteration
Abstract action that operates on an entire graph.
VertexContainer _vertices
Definition: hyper_graph.h:202