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"
39 #include "optimization_algorithm_property.h"
40 #include "hyper_graph_action.h"
41 #include "cache.h"
42 #include "robust_kernel.h"
43 #include "ownership.h"
44 
45 #include "g2o/stuff/macros.h"
46 #include "g2o/stuff/color_macros.h"
47 #include "g2o/stuff/string_tools.h"
48 #include "g2o/stuff/misc.h"
49 
50 namespace g2o {
51 
52   using namespace std;
53 
54   namespace {
printIdChain(std::ostream & os,const std::vector<int> & ids)55   std::ostream& printIdChain(std::ostream& os, const std::vector<int>& ids) {
56     for (size_t l = 0; l < ids.size(); ++l) {
57       if (l > 0) cerr << " <->";
58       cerr << " " << ids[l];
59     }
60     return os;
61   }
62   }  // namespace
63 
Vertex()64   OptimizableGraph::Vertex::Vertex() :
65     HyperGraph::Vertex(),
66     _graph(0), _userData(0), _hessianIndex(-1), _fixed(false), _marginalized(false),
67     _colInHessian(-1), _cacheContainer(0)
68   {
69   }
70 
cacheContainer()71   CacheContainer* OptimizableGraph::Vertex::cacheContainer(){
72     if (! _cacheContainer)
73       _cacheContainer = new CacheContainer(this);
74     return _cacheContainer;
75   }
76 
77 
updateCache()78   void OptimizableGraph::Vertex::updateCache(){
79     if (_cacheContainer){
80       _cacheContainer->setUpdateNeeded();
81       _cacheContainer->update();
82     }
83   }
84 
~Vertex()85   OptimizableGraph::Vertex::~Vertex()
86   {
87     delete _cacheContainer;
88     delete _userData;
89   }
90 
setEstimateData(const number_t * v)91   bool OptimizableGraph::Vertex::setEstimateData(const number_t* v)
92   {
93     bool ret = setEstimateDataImpl(v);
94     updateCache();
95     return ret;
96   }
97 
getEstimateData(number_t *) const98   bool OptimizableGraph::Vertex::getEstimateData(number_t *) const
99   {
100     return false;
101   }
102 
estimateDimension() const103   int OptimizableGraph::Vertex::estimateDimension() const
104   {
105     return -1;
106   }
107 
setMinimalEstimateData(const number_t * v)108   bool OptimizableGraph::Vertex::setMinimalEstimateData(const number_t* v)
109   {
110     bool ret = setMinimalEstimateDataImpl(v);
111     updateCache();
112     return ret;
113   }
114 
getMinimalEstimateData(number_t *) const115   bool OptimizableGraph::Vertex::getMinimalEstimateData(number_t *) const
116   {
117     return false;
118   }
119 
minimalEstimateDimension() const120   int OptimizableGraph::Vertex::minimalEstimateDimension() const
121   {
122     return -1;
123   }
124 
125 
Edge()126   OptimizableGraph::Edge::Edge() :
127     HyperGraph::Edge(),
128     _dimension(-1), _level(0), _robustKernel(nullptr)
129   {
130   }
131 
~Edge()132   OptimizableGraph::Edge::~Edge()
133   {
134     release(_robustKernel);
135   }
136 
graph()137   OptimizableGraph* OptimizableGraph::Edge::graph(){
138     if (! _vertices.size())
139       return nullptr;
140     OptimizableGraph::Vertex* v=(OptimizableGraph::Vertex*)_vertices[0];
141     if (!v)
142       return nullptr;
143     return v->graph();
144   }
145 
graph() const146   const OptimizableGraph* OptimizableGraph::Edge::graph() const{
147     if (! _vertices.size())
148       return nullptr;
149     const OptimizableGraph::Vertex* v=(const OptimizableGraph::Vertex*) _vertices[0];
150     if (!v)
151       return nullptr;
152     return v->graph();
153   }
154 
setParameterId(int argNum,int paramId)155   bool OptimizableGraph::Edge::setParameterId(int argNum, int paramId){
156     if ((int)_parameters.size()<=argNum)
157       return false;
158     if (argNum<0)
159       return false;
160     *_parameters[argNum] = 0;
161     _parameterIds[argNum] = paramId;
162     return true;
163   }
164 
resolveParameters()165   bool OptimizableGraph::Edge::resolveParameters() {
166     if (!graph()) {
167       cerr << __PRETTY_FUNCTION__ << ": edge not registered with a graph" << endl;
168       return false;
169     }
170 
171     assert (_parameters.size() == _parameterIds.size());
172     //cerr << __PRETTY_FUNCTION__ << ": encountered " << _parameters.size() << " parameters" << endl;
173     for (size_t i=0; i<_parameters.size(); i++){
174       int index = _parameterIds[i];
175       *_parameters[i] = graph()->parameter(index);
176       auto& aux = **_parameters[i];
177       if (typeid(aux).name()!=_parameterTypes[i]){
178         cerr << __PRETTY_FUNCTION__ << ": FATAL, parameter type mismatch - encountered " << typeid(aux).name() << "; should be " << _parameterTypes[i] << endl;
179       }
180       if (!*_parameters[i]) {
181         cerr << __PRETTY_FUNCTION__ << ": FATAL, *_parameters[i] == 0" << endl;
182         return false;
183       }
184     }
185     return true;
186   }
187 
setRobustKernel(RobustKernel * ptr)188   void OptimizableGraph::Edge::setRobustKernel(RobustKernel* ptr)
189   {
190     if (_robustKernel)
191       release(_robustKernel);
192 
193     _robustKernel = ptr;
194   }
195 
resolveCaches()196   bool OptimizableGraph::Edge::resolveCaches() {
197     return true;
198   }
199 
setMeasurementData(const number_t *)200   bool OptimizableGraph::Edge::setMeasurementData(const number_t *)
201   {
202     return false;
203   }
204 
getMeasurementData(number_t *) const205   bool OptimizableGraph::Edge::getMeasurementData(number_t *) const
206   {
207     return false;
208   }
209 
measurementDimension() const210   int OptimizableGraph::Edge::measurementDimension() const
211   {
212     return -1;
213   }
214 
setMeasurementFromState()215   bool OptimizableGraph::Edge::setMeasurementFromState(){
216     return false;
217   }
218 
OptimizableGraph()219   OptimizableGraph::OptimizableGraph()
220   {
221     _nextEdgeId = 0;
222     _graphActions.resize(AT_NUM_ELEMENTS);
223   }
224 
~OptimizableGraph()225   OptimizableGraph::~OptimizableGraph()
226   {
227     clear();
228     clearParameters();
229   }
230 
addVertex(OptimizableGraph::Vertex * ov,Data * userData)231   bool OptimizableGraph::addVertex(OptimizableGraph::Vertex* ov, Data* userData)
232   {
233     if (ov->id() <0){
234       cerr << __FUNCTION__ << ": FATAL, a vertex with (negative) ID " << ov->id() << " cannot be inserted in the graph" << endl;
235       assert(0 && "Invalid vertex id");
236       return false;
237     }
238     Vertex* inserted = vertex(ov->id());
239     if (inserted) {
240       cerr << __FUNCTION__ << ": FATAL, a vertex with ID " << ov->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     }
244     if (ov->_graph != nullptr && ov->_graph != this) {
245       cerr << __FUNCTION__ << ": FATAL, vertex with ID " << ov->id() << " has already registered with another graph " << ov->_graph << endl;
246       assert(0 && "Vertex already registered with another graph");
247       return false;
248     }
249     if (userData)
250       ov->setUserData(userData);
251     ov->_graph=this;
252     return HyperGraph::addVertex(ov);
253   }
254 
addVertex(HyperGraph::Vertex * v,Data * userData)255   bool OptimizableGraph::addVertex(HyperGraph::Vertex* v, Data* userData) {
256     OptimizableGraph::Vertex* ov = dynamic_cast<OptimizableGraph::Vertex*>(v);
257     assert(ov && "Vertex does not inherit from OptimizableGraph::Vertex");
258     if (!ov) return false;
259 
260     return addVertex(ov, userData);
261   }
262 
addEdge(OptimizableGraph::Edge * e)263   bool OptimizableGraph::addEdge(OptimizableGraph::Edge* e) {
264     OptimizableGraph* g = e->graph();
265 
266     if (g != nullptr && g != this) {
267       cerr << __FUNCTION__ << ": FATAL, edge with ID " << e->id()
268            << " has already registered with another graph " << g << endl;
269       assert(0 && "Edge already registered with another graph");
270       return false;
271     }
272 
273     bool eresult = HyperGraph::addEdge(e);
274     if (!eresult) return false;
275 
276     e->_internalId = _nextEdgeId++;
277     if (e->numUndefinedVertices()) return true;
278     if (!e->resolveParameters()) {
279       cerr << __FUNCTION__ << ": FATAL, cannot resolve parameters for edge " << e << endl;
280       return false;
281     }
282     if (!e->resolveCaches()) {
283       cerr << __FUNCTION__ << ": FATAL, cannot resolve caches for edge " << e << endl;
284       return false;
285     }
286 
287     _jacobianWorkspace.updateSize(e);
288 
289     return true;
290   }
291 
addEdge(HyperGraph::Edge * e_)292   bool OptimizableGraph::addEdge(HyperGraph::Edge* e_)
293   {
294     OptimizableGraph::Edge* e = dynamic_cast<OptimizableGraph::Edge*>(e_);
295     assert(e && "Edge does not inherit from OptimizableGraph::Edge");
296     if (!e)
297       return false;
298     return addEdge(e);
299   }
300 
setEdgeVertex(HyperGraph::Edge * e,int pos,HyperGraph::Vertex * v)301   bool OptimizableGraph::setEdgeVertex(HyperGraph::Edge* e, int pos, HyperGraph::Vertex* v) {
302     if (!HyperGraph::setEdgeVertex(e, pos, v)) {
303       return false;
304     }
305     if (!e->numUndefinedVertices()) {
306 #ifndef NDEBUG
307       OptimizableGraph::Edge* ee = dynamic_cast<OptimizableGraph::Edge*>(e);
308       assert(ee && "Edge is not a OptimizableGraph::Edge");
309 #else
310       OptimizableGraph::Edge* ee = static_cast<OptimizableGraph::Edge*>(e);
311 #endif
312       if (!ee->resolveParameters()) {
313         cerr << __FUNCTION__ << ": FATAL, cannot resolve parameters for edge " << e << endl;
314         return false;
315       }
316       if (!ee->resolveCaches()) {
317         cerr << __FUNCTION__ << ": FATAL, cannot resolve caches for edge " << e << endl;
318         return false;
319       }
320       _jacobianWorkspace.updateSize(e);
321     }
322     return true;
323   }
324 
optimize(int,bool)325   int OptimizableGraph::optimize(int /*iterations*/, bool /*online*/) {return 0;}
326 
chi2() const327 number_t OptimizableGraph::chi2() const
328 {
329   number_t chi = 0.0;
330   for (OptimizableGraph::EdgeSet::const_iterator it = this->edges().begin(); it != this->edges().end(); ++it) {
331     const OptimizableGraph::Edge* e = static_cast<const OptimizableGraph::Edge*>(*it);
332     chi += e->chi2();
333   }
334   return chi;
335 }
336 
push()337 void OptimizableGraph::push() {
338   forEachVertex([](OptimizableGraph::Vertex* v) { v->push(); });
339 }
340 
pop()341 void OptimizableGraph::pop() {
342   forEachVertex([](OptimizableGraph::Vertex* v) { v->pop(); });
343 }
344 
discardTop()345 void OptimizableGraph::discardTop() {
346   forEachVertex([](OptimizableGraph::Vertex* v) { v->discardTop(); });
347 }
348 
push(HyperGraph::VertexSet & vset)349 void OptimizableGraph::push(HyperGraph::VertexSet& vset) {
350   forEachVertex(vset, [](OptimizableGraph::Vertex* v) { v->push(); });
351 }
352 
pop(HyperGraph::VertexSet & vset)353 void OptimizableGraph::pop(HyperGraph::VertexSet& vset) {
354   forEachVertex(vset, [](OptimizableGraph::Vertex* v) { v->pop(); });
355 }
356 
discardTop(HyperGraph::VertexSet & vset)357 void OptimizableGraph::discardTop(HyperGraph::VertexSet& vset) {
358   forEachVertex(vset, [](OptimizableGraph::Vertex* v) { v->discardTop(); });
359 }
360 
setFixed(HyperGraph::VertexSet & vset,bool fixed)361 void OptimizableGraph::setFixed(HyperGraph::VertexSet& vset, bool fixed) {
362   forEachVertex(vset, [fixed](OptimizableGraph::Vertex* v) { v->setFixed(fixed); });
363 }
364 
forEachVertex(std::function<void (OptimizableGraph::Vertex *)> fn)365 void OptimizableGraph::forEachVertex(std::function<void(OptimizableGraph::Vertex*)> fn) {
366   for (auto it = _vertices.begin(); it != _vertices.end(); ++it) {
367     OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(it->second);
368     fn(v);
369   }
370 }
371 
forEachVertex(HyperGraph::VertexSet & vset,std::function<void (OptimizableGraph::Vertex *)> fn)372 void OptimizableGraph::forEachVertex(HyperGraph::VertexSet& vset,
373                                      std::function<void(OptimizableGraph::Vertex*)> fn) {
374   for (auto it = vset.begin(); it != vset.end(); ++it) {
375     OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it);
376     fn(v);
377   }
378 }
379 
load(istream & is)380 bool OptimizableGraph::load(istream& is)
381 {
382   set<string> warnedUnknownTypes;
383   stringstream currentLine;
384   string token;
385 
386   Factory* factory = Factory::instance();
387   HyperGraph::GraphElemBitset elemBitset;
388   elemBitset[HyperGraph::HGET_PARAMETER] = 1;
389   elemBitset.flip();
390 
391   HyperGraph::GraphElemBitset elemParamBitset;
392   elemParamBitset[HyperGraph::HGET_PARAMETER] = 1;
393 
394   HyperGraph::DataContainer* previousDataContainer = 0;
395   Data* previousData = 0;
396 
397   int lineNumber = 0;
398   while (1) {
399     int bytesRead = readLine(is, currentLine);
400     lineNumber++;
401     if (bytesRead == -1) break;
402     currentLine >> token;
403     // cerr << "Token=" << token << endl;
404     if (bytesRead == 0 || token.size() == 0 || token[0] == '#') continue;
405 
406     // handle commands encoded in the file
407     if (token == "FIX") {
408       int id;
409       while (currentLine >> id) {
410         OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(vertex(id));
411         if (v) {
412 #ifndef NDEBUG
413           cerr << "Fixing vertex " << v->id() << endl;
414 #endif
415           v->setFixed(true);
416         } else {
417           cerr << "Warning: Unable to fix vertex with id " << id << ". Not found in the graph."
418                << endl;
419         }
420       }
421       continue;
422     }
423 
424     // do the mapping to an internal type if it matches
425     if (_renamedTypesLookup.size() > 0) {
426       map<string, string>::const_iterator foundIt = _renamedTypesLookup.find(token);
427       if (foundIt != _renamedTypesLookup.end()) {
428         token = foundIt->second;
429       }
430     }
431 
432     if (!factory->knowsTag(token)) {
433       if (warnedUnknownTypes.count(token) != 1) {
434         warnedUnknownTypes.insert(token);
435         cerr << CL_RED(__PRETTY_FUNCTION__ << " unknown type: " << token) << endl;
436       }
437       continue;
438     }
439 
440     // first handle the parameters
441     HyperGraph::HyperGraphElement* pelement = factory->construct(token, elemParamBitset);
442     if (pelement) {  // not a parameter or otherwise unknown tag
443       assert(pelement->elementType() == HyperGraph::HGET_PARAMETER && "Should be a param");
444       Parameter* p = static_cast<Parameter*>(pelement);
445       int pid;
446       currentLine >> pid;
447       p->setId(pid);
448       bool r = p->read(currentLine);
449       if (!r) {
450         cerr << __PRETTY_FUNCTION__ << ": Error reading data " << token << " for parameter " << pid
451              << " at line " << lineNumber << endl;
452         delete p;
453       } else {
454         if (!_parameters.addParameter(p)) {
455           cerr << __PRETTY_FUNCTION__ << ": Parameter of type:" << token << " id:" << pid
456                << " already defined"
457                << " at line " << lineNumber << endl;
458         }
459       }
460       continue;
461     }
462 
463     HyperGraph::HyperGraphElement* element = factory->construct(token, elemBitset);
464     if (dynamic_cast<Vertex*>(element)) {  // it's a vertex type
465       previousData = 0;
466       Vertex* v = static_cast<Vertex*>(element);
467       int id;
468       currentLine >> id;
469       bool r = v->read(currentLine);
470       if (!r)
471         cerr << __PRETTY_FUNCTION__ << ": Error reading vertex " << token << " " << id
472              << " at line " << lineNumber << endl;
473       v->setId(id);
474       if (!addVertex(v)) {
475         cerr << __PRETTY_FUNCTION__ << ": Failure adding Vertex, " << token << " " << id
476              << " at line " << lineNumber << endl;
477         delete v;
478       } else {
479         previousDataContainer = v;
480       }
481     } else if (dynamic_cast<Edge*>(element)) {
482       // cerr << "it is an edge" << endl;
483       previousData = 0;
484       Edge* e = static_cast<Edge*>(element);
485       int numV = e->vertices().size();
486 
487       vector<int> ids;
488       if (e->vertices().size() != 0) {
489         ids.resize(e->vertices().size());
490         for (int l = 0; l < numV; ++l) currentLine >> ids[l];
491       } else {
492         string buff;  // reading the IDs of a dynamically sized edge
493         while (currentLine >> buff) {
494           if (buff == "||") break;
495           ids.push_back(atoi(buff.c_str()));
496           currentLine >> buff;
497         }
498         e->resize(numV);
499       }
500       bool vertsOkay = true;
501       for (size_t l = 0; l < ids.size(); ++l) {
502         int vertexId = ids[l];
503         if (vertexId != HyperGraph::UnassignedId) {
504           HyperGraph::Vertex* v = vertex(vertexId);
505           if (!v) {
506             vertsOkay = false;
507             break;
508           }
509           e->setVertex(l, v);
510         }
511       }
512       if (!vertsOkay) {
513         cerr << __PRETTY_FUNCTION__ << ": Unable to find vertices for edge " << token << " at line "
514              << lineNumber << " IDs: ";
515         printIdChain(cerr, ids) << std::endl;
516         delete e;
517         e = nullptr;
518       } else {
519         bool r = e->read(currentLine);
520         if (!r || !addEdge(e)) {
521           cerr << __PRETTY_FUNCTION__ << ": Unable to add edge " << token << " at line "
522                << lineNumber << " IDs: ";
523           printIdChain(cerr, ids) << std::endl;
524           delete e;
525           e = nullptr;
526         }
527       }
528 
529       previousDataContainer = e;
530     } else if (dynamic_cast<Data*>(element)) {  // reading in the data packet for the vertex
531       // cerr << "read data packet " << token << " vertex " << previousVertex->id() << endl;
532       Data* d = static_cast<Data*>(element);
533       bool r = d->read(currentLine);
534       if (!r) {
535         cerr << __PRETTY_FUNCTION__ << ": Error reading data " << token << " at line " << lineNumber
536              << " IDs: " << endl;
537         delete d;
538         previousData = 0;
539       } else if (previousData) {
540         previousData->setNext(d);
541         d->setDataContainer(previousData->dataContainer());
542         previousData = d;
543       } else if (previousDataContainer) {
544         previousDataContainer->setUserData(d);
545         d->setDataContainer(previousDataContainer);
546         previousData = d;
547         previousDataContainer = 0;
548       } else {
549         cerr << __PRETTY_FUNCTION__ << ": got data element, but no data container available"
550              << endl;
551         delete d;
552         previousData = 0;
553       }
554     }
555   }  // while read line
556 
557 #ifndef NDEBUG
558   cerr << "Loaded " << _parameters.size() << " parameters" << endl;
559 #endif
560 
561   return true;
562 }
563 
load(const char * filename)564 bool OptimizableGraph::load(const char* filename)
565 {
566   ifstream ifs(filename);
567   if (!ifs) {
568     cerr << __PRETTY_FUNCTION__ << " unable to open file " << filename << endl;
569     return false;
570   }
571   return load(ifs);
572 }
573 
save(const char * filename,int level) const574 bool OptimizableGraph::save(const char* filename, int level) const
575 {
576   ofstream ofs(filename);
577   if (!ofs)
578     return false;
579   return save(ofs, level);
580 }
581 
save(ostream & os,int level) const582 bool OptimizableGraph::save(ostream& os, int level) const
583 {
584   // write the parameters to the top of the file
585   if (!_parameters.write(os)) return false;
586   set<Vertex*, VertexIDCompare> verticesToSave; // set sorted by ID
587   for (HyperGraph::EdgeSet::const_iterator it = edges().begin(); it != edges().end(); ++it) {
588     OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
589     if (e->level() == level) {
590       for (auto it = e->vertices().begin(); it != e->vertices().end(); ++it) {
591         if (*it) verticesToSave.insert(static_cast<OptimizableGraph::Vertex*>(*it));
592       }
593     }
594   }
595 
596   for (auto v : verticesToSave) saveVertex(os, v);
597 
598   std::vector<HyperGraph::Edge*> edgesToSave;
599   std::copy_if(edges().begin(), edges().end(), std::back_inserter(edgesToSave),
600                [level](const HyperGraph::Edge* ee) {
601                  const OptimizableGraph::Edge* e = dynamic_cast<const OptimizableGraph::Edge*>(ee);
602                  return (e->level() == level);
603                });
604   sort(edgesToSave.begin(), edgesToSave.end(), EdgeIDCompare());
605   for (auto e : edgesToSave) saveEdge(os, static_cast<Edge*>(e));
606 
607   return os.good();
608 }
609 
saveSubset(ostream & os,HyperGraph::VertexSet & vset,int level)610 bool OptimizableGraph::saveSubset(ostream& os, HyperGraph::VertexSet& vset, int level) {
611   if (!_parameters.write(os)) return false;
612 
613   for (auto v : vset) saveVertex(os, static_cast<Vertex*>(v));
614 
615   for (HyperGraph::EdgeSet::const_iterator it = edges().begin(); it != edges().end(); ++it) {
616     OptimizableGraph::Edge* e = dynamic_cast<OptimizableGraph::Edge*>(*it);
617     if (e->level() != level) continue;
618 
619     bool verticesInEdge = true;
620     for (vector<HyperGraph::Vertex*>::const_iterator it = e->vertices().begin(); it != e->vertices().end(); ++it) {
621       if (vset.find(*it) == vset.end()) {
622         verticesInEdge = false;
623         break;
624       }
625     }
626     if (!verticesInEdge) continue;
627 
628     saveEdge(os, e);
629   }
630 
631   return os.good();
632 }
633 
saveSubset(ostream & os,HyperGraph::EdgeSet & eset)634 bool OptimizableGraph::saveSubset(ostream& os, HyperGraph::EdgeSet& eset) {
635   if (!_parameters.write(os)) return false;
636   HyperGraph::VertexSet vset;
637   for (auto e : eset)
638     for (auto v : e->vertices())
639       if (v) vset.insert(v);
640 
641   for (auto v : vset) saveVertex(os, static_cast<Vertex*>(v));
642   for (auto e : eset) saveEdge(os, static_cast<Edge*>(e));
643   return os.good();
644 }
645 
maxDimension() const646 int OptimizableGraph::maxDimension() const{
647   int maxDim=0;
648   for (HyperGraph::VertexIDMap::const_iterator it=vertices().begin(); it!=vertices().end(); ++it){
649     const OptimizableGraph::Vertex* v= static_cast< const OptimizableGraph::Vertex*>(it->second);
650     maxDim = (std::max)(maxDim, v->dimension());
651   }
652   return maxDim;
653 }
654 
setRenamedTypesFromString(const std::string & types)655 void OptimizableGraph::setRenamedTypesFromString(const std::string& types)
656 {
657   Factory* factory = Factory::instance();
658   vector<string> typesMap = strSplit(types, ",");
659   for (size_t i = 0; i < typesMap.size(); ++i) {
660     vector<string> m = strSplit(typesMap[i], "=");
661     if (m.size() != 2) {
662       cerr << __PRETTY_FUNCTION__ << ": unable to extract type map from " << typesMap[i] << endl;
663       continue;
664     }
665     string typeInFile = trim(m[0]);
666     string loadedType = trim(m[1]);
667     if (! factory->knowsTag(loadedType)) {
668       cerr << __PRETTY_FUNCTION__ << ": unknown type " << loadedType << endl;
669       continue;
670     }
671 
672     _renamedTypesLookup[typeInFile] = loadedType;
673   }
674 
675   cerr << "# load look up table" << endl;
676   for (std::map<std::string, std::string>::const_iterator it = _renamedTypesLookup.begin(); it != _renamedTypesLookup.end(); ++it) {
677     cerr << "#\t" << it->first << " -> " << it->second << endl;
678   }
679 }
680 
isSolverSuitable(const OptimizationAlgorithmProperty & solverProperty,const std::set<int> & vertDims_) const681 bool OptimizableGraph::isSolverSuitable(const OptimizationAlgorithmProperty& solverProperty, const std::set<int>& vertDims_) const
682 {
683   std::set<int> auxDims;
684   if (vertDims_.size() == 0) {
685     auxDims = dimensions();
686   }
687   const set<int>& vertDims = vertDims_.size() == 0 ? auxDims : vertDims_;
688   bool suitableSolver = true;
689   if (vertDims.size() == 2) {
690     if (solverProperty.requiresMarginalize) {
691       suitableSolver = vertDims.count(solverProperty.poseDim) == 1 && vertDims.count(solverProperty.landmarkDim) == 1;
692     }
693     else {
694       suitableSolver = solverProperty.poseDim == -1;
695     }
696   } else if (vertDims.size() == 1) {
697     suitableSolver = vertDims.count(solverProperty.poseDim) == 1 || solverProperty.poseDim == -1;
698   } else {
699     suitableSolver = solverProperty.poseDim == -1 && !solverProperty.requiresMarginalize;
700   }
701   return suitableSolver;
702 }
703 
dimensions() const704 std::set<int> OptimizableGraph::dimensions() const
705 {
706   std::set<int> auxDims;
707   for (VertexIDMap::const_iterator it = vertices().begin(); it != vertices().end(); ++it) {
708     OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(it->second);
709     auxDims.insert(v->dimension());
710   }
711   return auxDims;
712 }
713 
performActions(int iter,HyperGraphActionSet & actions)714 void OptimizableGraph::performActions(int iter, HyperGraphActionSet& actions)
715 {
716   if (actions.size() > 0) {
717     HyperGraphAction::ParametersIteration params(iter);
718     for (HyperGraphActionSet::iterator it = actions.begin(); it != actions.end(); ++it) {
719       (*(*it))(this, &params);
720     }
721   }
722 }
723 
preIteration(int iter)724 void OptimizableGraph::preIteration(int iter)
725 {
726   performActions(iter, _graphActions[AT_PREITERATION]);
727 }
728 
postIteration(int iter)729 void OptimizableGraph::postIteration(int iter)
730 {
731   performActions(iter, _graphActions[AT_POSTITERATION]);
732 }
733 
addPostIterationAction(HyperGraphAction * action)734 bool OptimizableGraph::addPostIterationAction(HyperGraphAction* action)
735 {
736   std::pair<HyperGraphActionSet::iterator, bool> insertResult = _graphActions[AT_POSTITERATION].insert(action);
737   return insertResult.second;
738 }
739 
addPreIterationAction(HyperGraphAction * action)740 bool OptimizableGraph::addPreIterationAction(HyperGraphAction* action)
741 {
742   std::pair<HyperGraphActionSet::iterator, bool> insertResult = _graphActions[AT_PREITERATION].insert(action);
743   return insertResult.second;
744 }
745 
removePreIterationAction(HyperGraphAction * action)746 bool OptimizableGraph::removePreIterationAction(HyperGraphAction* action)
747 {
748   return _graphActions[AT_PREITERATION].erase(action) > 0;
749 }
750 
removePostIterationAction(HyperGraphAction * action)751 bool OptimizableGraph::removePostIterationAction(HyperGraphAction* action)
752 {
753   return _graphActions[AT_POSTITERATION].erase(action) > 0;
754 }
755 
saveUserData(std::ostream & os,HyperGraph::Data * d) const756 bool OptimizableGraph::saveUserData(std::ostream& os, HyperGraph::Data* d) const {
757   Factory* factory = Factory::instance();
758   while (d) {  // write the data packet for the vertex
759     string tag = factory->tag(d);
760     if (tag.size() > 0) {
761       os << tag << " ";
762       d->write(os);
763       os << endl;
764     }
765     d = d->next();
766   }
767   return os.good();
768 }
769 
saveVertex(std::ostream & os,OptimizableGraph::Vertex * v) const770 bool OptimizableGraph::saveVertex(std::ostream& os, OptimizableGraph::Vertex* v) const
771 {
772   Factory* factory = Factory::instance();
773   string tag = factory->tag(v);
774   if (tag.size() > 0) {
775     os << tag << " " << v->id() << " ";
776     v->write(os);
777     os << endl;
778     saveUserData(os, v->userData());
779     if (v->fixed()) {
780       os << "FIX " << v->id() << endl;
781     }
782     return os.good();
783   }
784   return false;
785 }
786 
saveParameter(std::ostream & os,Parameter * p) const787 bool OptimizableGraph::saveParameter(std::ostream& os, Parameter* p) const
788 {
789   Factory* factory = Factory::instance();
790   string tag = factory->tag(p);
791   if (tag.size() > 0) {
792     os << tag << " " << p->id() << " ";
793     p->write(os);
794     os << endl;
795   }
796   return os.good();
797 }
798 
saveEdge(std::ostream & os,OptimizableGraph::Edge * e) const799 bool OptimizableGraph::saveEdge(std::ostream& os, OptimizableGraph::Edge* e) const
800 {
801   Factory* factory = Factory::instance();
802   string tag = factory->tag(e);
803   if (tag.size() > 0) {
804     os << tag << " ";
805     for (vector<HyperGraph::Vertex*>::const_iterator it = e->vertices().begin(); it != e->vertices().end(); ++it) {
806       int vertexId = (*it) ? (*it)->id() : HyperGraph::UnassignedId;
807       os << vertexId << " ";
808     }
809     e->write(os);
810     os << endl;
811     saveUserData(os, e->userData());
812     return os.good();
813   }
814   return false;
815 }
816 
clearParameters()817 void OptimizableGraph::clearParameters()
818 {
819   HyperGraph::clear();
820   _parameters.clear();
821 }
822 
verifyInformationMatrices(bool verbose) const823 bool OptimizableGraph::verifyInformationMatrices(bool verbose) const
824 {
825   bool allEdgeOk = true;
826   Eigen::SelfAdjointEigenSolver<MatrixX> eigenSolver;
827   for (OptimizableGraph::EdgeSet::const_iterator it = edges().begin(); it != edges().end(); ++it) {
828     OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
829     MatrixX::MapType information(e->informationData(), e->dimension(), e->dimension());
830     // test on symmetry
831     bool isSymmetric = information.transpose() == information;
832     bool okay = isSymmetric;
833     if (isSymmetric) {
834       // compute the eigenvalues
835       eigenSolver.compute(information, Eigen::EigenvaluesOnly);
836       bool isSPD = eigenSolver.eigenvalues()(0) >= 0.;
837       okay = okay && isSPD;
838     }
839     allEdgeOk = allEdgeOk && okay;
840     if (! okay) {
841       if (verbose) {
842         if (! isSymmetric)
843           cerr << "Information Matrix for an edge is not symmetric:";
844         else
845           cerr << "Information Matrix for an edge is not SPD:";
846         for (size_t i = 0; i < e->vertices().size(); ++i)
847           cerr << " " << e->vertex(i)->id();
848         if (isSymmetric)
849           cerr << "\teigenvalues: " << eigenSolver.eigenvalues().transpose();
850         cerr << endl;
851       }
852     }
853   }
854   return allEdgeOk;
855 }
856 
initMultiThreading()857 bool OptimizableGraph::initMultiThreading()
858 {
859 # if (defined G2O_OPENMP) && EIGEN_VERSION_AT_LEAST(3,1,0)
860   Eigen::initParallel();
861 # endif
862   return true;
863 }
864 
865 } // end namespace
866 
867