g2o
Loading...
Searching...
No Matches
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 <Eigen/Dense>
30#include <algorithm>
31#include <cassert>
32#include <fstream>
33#include <iomanip>
34#include <iostream>
35#include <iterator>
36#include <sstream>
37
38#include "cache.h"
39#include "estimate_propagator.h"
40#include "factory.h"
42#include "g2o/stuff/logger.h"
44#include "g2o/stuff/macros.h"
45#include "g2o/stuff/misc.h"
47#include "hyper_graph_action.h"
49#include "ownership.h"
50#include "robust_kernel.h"
51
52namespace g2o {
53
54using namespace std;
55
57 : HyperGraph::Vertex(),
58 _graph(0),
59 _userData(0),
60 _hessianIndex(-1),
61 _fixed(false),
62 _marginalized(false),
63 _colInHessian(-1),
64 _cacheContainer(0) {}
65
67 if (!_cacheContainer) _cacheContainer = new CacheContainer(this);
68 return _cacheContainer;
69}
70
72 if (_cacheContainer) {
73 _cacheContainer->setUpdateNeeded();
74 _cacheContainer->update();
75 }
76}
77
79 delete _cacheContainer;
80 delete _userData;
81}
82
84 bool ret = setEstimateDataImpl(v);
85 updateCache();
86 return ret;
87}
88
89bool OptimizableGraph::Vertex::getEstimateData(double*) const { return false; }
90
92
94 bool ret = setMinimalEstimateDataImpl(v);
95 updateCache();
96 return ret;
97}
98
100 return false;
101}
102
104
106 : HyperGraph::Edge(), _dimension(-1), _level(0), _robustKernel(nullptr) {}
107
109
111 if (!_vertices.size()) return nullptr;
113 if (!v) return nullptr;
114 return v->graph();
115}
116
118 if (!_vertices.size()) return nullptr;
119 const OptimizableGraph::Vertex* v =
121 if (!v) return nullptr;
122 return v->graph();
123}
124
125bool OptimizableGraph::Edge::setParameterId(int argNum, int paramId) {
126 if ((int)_parameters.size() <= argNum) return false;
127 if (argNum < 0) return false;
128 *_parameters[argNum] = 0;
129 _parameterIds[argNum] = paramId;
130 return true;
131}
132
134 if (!graph()) {
135 G2O_ERROR("{}: edge not registered with a graph", __PRETTY_FUNCTION__);
136 return false;
137 }
138
139 assert(_parameters.size() == _parameterIds.size());
140 for (size_t i = 0; i < _parameters.size(); i++) {
141 int index = _parameterIds[i];
142 *_parameters[i] = graph()->parameter(index);
143 auto& aux = **_parameters[i];
144 if (typeid(aux).name() != _parameterTypes[i]) {
145 G2O_ERROR(
146 "{}: FATAL, parameter type mismatch - encountered {}; should be {}",
147 __PRETTY_FUNCTION__, typeid(aux).name(), _parameterTypes[i]);
148 }
149 if (!*_parameters[i]) {
150 G2O_ERROR("{}: FATAL, *_parameters[i] == 0", __PRETTY_FUNCTION__);
151 return false;
152 }
153 }
154 return true;
155}
156
158 if (_robustKernel) release(_robustKernel);
159
160 _robustKernel = ptr;
161}
162
164
165bool OptimizableGraph::Edge::setMeasurementData(const double*) { return false; }
166
167bool OptimizableGraph::Edge::getMeasurementData(double*) const { return false; }
168
170
172
177
182
184 if (ov->id() < 0) {
185 G2O_ERROR(
186 "{}: FATAL, a vertex with (negative) ID {} cannot be inserted into the "
187 "graph",
188 __PRETTY_FUNCTION__, ov->id());
189 assert(0 && "Invalid vertex id");
190 return false;
191 }
192 Vertex* inserted = vertex(ov->id());
193 if (inserted) {
194 G2O_WARN(
195 "{}: a vertex with ID {} has already been registered with this "
196 "graph",
197 __PRETTY_FUNCTION__, ov->id());
198 return false;
199 }
200 if (ov->_graph != nullptr && ov->_graph != this) {
201 G2O_ERROR(
202 "{}: FATAL, vertex with ID {} has already been registered with another "
203 "graph {}",
204 __PRETTY_FUNCTION__, ov->id(), static_cast<void*>(ov->_graph));
205 return false;
206 }
207 if (userData) ov->setUserData(userData);
208 ov->_graph = this;
209 return HyperGraph::addVertex(ov);
210}
211
214 assert(ov && "Vertex does not inherit from OptimizableGraph::Vertex");
215 if (!ov) return false;
216
217 return addVertex(ov, userData);
218}
219
221 OptimizableGraph* g = e->graph();
222
223 if (g != nullptr && g != this) {
224 G2O_ERROR(
225 "{}: FATAL, edge with ID {} has already registered with another graph "
226 "{}",
227 __PRETTY_FUNCTION__, e->id(), static_cast<void*>(g));
228 return false;
229 }
230
231 bool eresult = HyperGraph::addEdge(e);
232 if (!eresult) return false;
233
235 if (e->numUndefinedVertices()) return true;
236 if (!e->resolveParameters()) {
237 G2O_ERROR("{}: FATAL, cannot resolve parameters for edge {}",
238 static_cast<void*>(e));
239 return false;
240 }
241 if (!e->resolveCaches()) {
242 G2O_ERROR("{}: FATAL, cannot resolve caches for edge {}",
243 static_cast<void*>(e));
244 return false;
245 }
246
248
249 return true;
250}
251
253 OptimizableGraph::Edge* e = dynamic_cast<OptimizableGraph::Edge*>(e_);
254 assert(e && "Edge does not inherit from OptimizableGraph::Edge");
255 if (!e) return false;
256 return addEdge(e);
257}
258
261 if (!HyperGraph::setEdgeVertex(e, pos, v)) {
262 return false;
263 }
264 if (!e->numUndefinedVertices()) {
265#ifndef NDEBUG
266 OptimizableGraph::Edge* ee = dynamic_cast<OptimizableGraph::Edge*>(e);
267 assert(ee && "Edge is not a OptimizableGraph::Edge");
268#else
269 OptimizableGraph::Edge* ee = static_cast<OptimizableGraph::Edge*>(e);
270#endif
271 if (!ee->resolveParameters()) {
272 G2O_ERROR("{}: FATAL, cannot resolve parameters for edge {}",
273 static_cast<void*>(e));
274 return false;
275 }
276 if (!ee->resolveCaches()) {
277 G2O_ERROR("{}: FATAL, cannot resolve caches for edge {}",
278 static_cast<void*>(e));
279 return false;
280 }
282 }
283 return true;
284}
285
286int OptimizableGraph::optimize(int /*iterations*/, bool /*online*/) {
287 return 0;
288}
289
291 double chi = 0.0;
292 for (OptimizableGraph::EdgeSet::const_iterator it = this->edges().begin();
293 it != this->edges().end(); ++it) {
294 const OptimizableGraph::Edge* e =
295 static_cast<const OptimizableGraph::Edge*>(*it);
296 chi += e->chi2();
297 }
298 return chi;
299}
300
304
308
312
316
320
324
326 forEachVertex(vset,
327 [fixed](OptimizableGraph::Vertex* v) { v->setFixed(fixed); });
328}
329
331 std::function<void(OptimizableGraph::Vertex*)> fn) {
332 for (auto it = _vertices.begin(); it != _vertices.end(); ++it) {
334 static_cast<OptimizableGraph::Vertex*>(it->second);
335 fn(v);
336 }
337}
338
341 std::function<void(OptimizableGraph::Vertex*)> fn) {
342 for (auto it = vset.begin(); it != vset.end(); ++it) {
344 fn(v);
345 }
346}
347
348bool OptimizableGraph::load(istream& is) {
349 set<string> warnedUnknownTypes;
350 stringstream currentLine;
351 string token;
352
353 Factory* factory = Factory::instance();
355 elemBitset[HyperGraph::HGET_PARAMETER] = 1;
356 elemBitset.flip();
357
358 HyperGraph::GraphElemBitset elemParamBitset;
359 elemParamBitset[HyperGraph::HGET_PARAMETER] = 1;
360
361 HyperGraph::DataContainer* previousDataContainer = 0;
362 Data* previousData = 0;
363
364 int lineNumber = 0;
365 while (1) {
366 int bytesRead = readLine(is, currentLine);
367 lineNumber++;
368 if (bytesRead == -1) break;
369 currentLine >> token;
370 if (bytesRead == 0 || token.size() == 0 || token[0] == '#') continue;
371
372 // handle commands encoded in the file
373 if (token == "FIX") {
374 int id;
375 while (currentLine >> id) {
377 static_cast<OptimizableGraph::Vertex*>(vertex(id));
378 if (v) {
379#ifndef NDEBUG
380 G2O_DEBUG("Fixing vertex {}", v->id());
381#endif
382 v->setFixed(true);
383 } else {
384 G2O_WARN("Unable to fix vertex with id {}. Not found in the graph.",
385 id);
386 }
387 }
388 continue;
389 }
390
391 // do the mapping to an internal type if it matches
392 if (_renamedTypesLookup.size() > 0) {
393 map<string, string>::const_iterator foundIt =
395 if (foundIt != _renamedTypesLookup.end()) {
396 token = foundIt->second;
397 }
398 }
399
400 if (!factory->knowsTag(token)) {
401 if (warnedUnknownTypes.count(token) != 1) {
402 warnedUnknownTypes.insert(token);
403 G2O_ERROR("{}: Unknown type {}", __PRETTY_FUNCTION__, token);
404 }
405 continue;
406 }
407
408 // first handle the parameters
409 HyperGraph::HyperGraphElement* pelement =
410 factory->construct(token, elemParamBitset);
411 if (pelement) { // not a parameter or otherwise unknown tag
412 assert(pelement->elementType() == HyperGraph::HGET_PARAMETER &&
413 "Should be a param");
414 Parameter* p = static_cast<Parameter*>(pelement);
415 int pid;
416 currentLine >> pid;
417 p->setId(pid);
418 bool r = p->read(currentLine);
419 if (!r) {
420 G2O_ERROR("{}: reading data {} for parameter {} at line ",
421 __PRETTY_FUNCTION__, pid, lineNumber);
422 delete p;
423 } else {
424 if (!_parameters.addParameter(p)) {
425 G2O_ERROR(
426 "{}: Parameter of type: {} id: {} already defined at line {}",
427 __PRETTY_FUNCTION__, token, pid, lineNumber);
428 }
429 }
430 continue;
431 }
432
433 HyperGraph::HyperGraphElement* element =
434 factory->construct(token, elemBitset);
435 if (dynamic_cast<Vertex*>(element)) { // it's a vertex type
436 previousData = 0;
437 Vertex* v = static_cast<Vertex*>(element);
438 int id;
439 currentLine >> id;
440 bool r = v->read(currentLine);
441 if (!r)
442 G2O_ERROR("{}: Error reading vertex {} {} at line {}",
443 __PRETTY_FUNCTION__, token, id, lineNumber);
444 v->setId(id);
445 if (!addVertex(v)) {
446 G2O_ERROR("{}: Failure adding Vertex {} {} at line {}",
447 __PRETTY_FUNCTION__, token, id, lineNumber);
448 delete v;
449 } else {
450 previousDataContainer = v;
451 }
452 } else if (dynamic_cast<Edge*>(element)) {
453 previousData = 0;
454 Edge* e = static_cast<Edge*>(element);
455 int numV = e->vertices().size();
456
457 vector<int> ids;
458 if (e->vertices().size() != 0) {
459 ids.resize(e->vertices().size());
460 for (int l = 0; l < numV; ++l) currentLine >> ids[l];
461 } else {
462 string buff; // reading the IDs of a dynamically sized edge
463 while (currentLine >> buff) {
464 if (buff == "||") break;
465 ids.push_back(atoi(buff.c_str()));
466 currentLine >> buff;
467 }
468 e->resize(numV);
469 }
470 bool vertsOkay = true;
471 for (size_t l = 0; l < ids.size(); ++l) {
472 int vertexId = ids[l];
473 if (vertexId != HyperGraph::UnassignedId) {
474 HyperGraph::Vertex* v = vertex(vertexId);
475 if (!v) {
476 vertsOkay = false;
477 break;
478 }
479 e->setVertex(l, v);
480 }
481 }
482 if (!vertsOkay) {
483 G2O_ERROR("{}: Unable to find vertices for edge {} at line {} IDs: {}",
484 __PRETTY_FUNCTION__, token, lineNumber, fmt::join(ids, " "));
485 delete e;
486 e = nullptr;
487 } else {
488 bool r = e->read(currentLine);
489 if (!r || !addEdge(e)) {
490 G2O_ERROR("{}: Unable to add edge {} at line {} IDs: {}",
491 __PRETTY_FUNCTION__, token, lineNumber,
492 fmt::join(ids, " "));
493 delete e;
494 e = nullptr;
495 }
496 }
497
498 previousDataContainer = e;
499 } else if (dynamic_cast<Data*>(
500 element)) { // reading in the data packet for the vertex
501 Data* d = static_cast<Data*>(element);
502 bool r = d->read(currentLine);
503 if (!r) {
504 G2O_ERROR("{}: Error reading data {} at line {}", __PRETTY_FUNCTION__,
505 token, lineNumber);
506 delete d;
507 previousData = 0;
508 } else if (previousData) {
509 previousData->setNext(d);
510 d->setDataContainer(previousData->dataContainer());
511 previousData = d;
512 } else if (previousDataContainer) {
513 previousDataContainer->setUserData(d);
514 d->setDataContainer(previousDataContainer);
515 previousData = d;
516 previousDataContainer = 0;
517 } else {
518 G2O_ERROR("{}: got data element, but no data container available",
520 delete d;
521 previousData = 0;
522 }
523 }
524 } // while read line
525
526#ifndef NDEBUG
527 G2O_DEBUG("Loaded {} parameters", _parameters.size());
528#endif
529
530 return true;
531}
532
533bool OptimizableGraph::load(const char* filename) {
534 ifstream ifs(filename);
535 if (!ifs) {
536 G2O_ERROR("Unable to open file {}", filename);
537 return false;
538 }
539 return load(ifs);
540}
541
542bool OptimizableGraph::save(const char* filename, int level) const {
543 ofstream ofs(filename);
544 if (!ofs) return false;
545 return save(ofs, level);
546}
547
548bool OptimizableGraph::save(ostream& os, int level) const {
549 // write the parameters to the top of the file
550 if (!_parameters.write(os)) return false;
551 set<Vertex*, VertexIDCompare> verticesToSave; // set sorted by ID
552 for (HyperGraph::EdgeSet::const_iterator it = edges().begin();
553 it != edges().end(); ++it) {
554 OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
555 if (e->level() == level) {
556 for (auto it = e->vertices().begin(); it != e->vertices().end(); ++it) {
557 if (*it)
558 verticesToSave.insert(static_cast<OptimizableGraph::Vertex*>(*it));
559 }
560 }
561 }
562
563 for (auto v : verticesToSave) saveVertex(os, v);
564
565 std::vector<HyperGraph::Edge*> edgesToSave;
566 std::copy_if(edges().begin(), edges().end(), std::back_inserter(edgesToSave),
567 [level](const HyperGraph::Edge* ee) {
568 const OptimizableGraph::Edge* e =
569 dynamic_cast<const OptimizableGraph::Edge*>(ee);
570 return (e->level() == level);
571 });
572 sort(edgesToSave.begin(), edgesToSave.end(), EdgeIDCompare());
573 for (auto e : edgesToSave) saveEdge(os, static_cast<Edge*>(e));
574
575 return os.good();
576}
577
579 int level) {
580 if (!_parameters.write(os)) return false;
581
582 for (auto v : vset) saveVertex(os, static_cast<Vertex*>(v));
583
584 for (HyperGraph::EdgeSet::const_iterator it = edges().begin();
585 it != edges().end(); ++it) {
586 OptimizableGraph::Edge* e = dynamic_cast<OptimizableGraph::Edge*>(*it);
587 if (e->level() != level) continue;
588
589 bool verticesInEdge = true;
590 for (vector<HyperGraph::Vertex*>::const_iterator it = e->vertices().begin();
591 it != e->vertices().end(); ++it) {
592 if (vset.find(*it) == vset.end()) {
593 verticesInEdge = false;
594 break;
595 }
596 }
597 if (!verticesInEdge) continue;
598
599 saveEdge(os, e);
600 }
601
602 return os.good();
603}
604
605bool OptimizableGraph::saveSubset(ostream& os, HyperGraph::EdgeSet& eset) {
606 if (!_parameters.write(os)) return false;
608 for (auto e : eset)
609 for (auto v : e->vertices())
610 if (v) vset.insert(v);
611
612 for (auto v : vset) saveVertex(os, static_cast<Vertex*>(v));
613 for (auto e : eset) saveEdge(os, static_cast<Edge*>(e));
614 return os.good();
615}
616
618 int maxDim = 0;
619 for (HyperGraph::VertexIDMap::const_iterator it = vertices().begin();
620 it != vertices().end(); ++it) {
621 const OptimizableGraph::Vertex* v =
622 static_cast<const OptimizableGraph::Vertex*>(it->second);
623 maxDim = (std::max)(maxDim, v->dimension());
624 }
625 return maxDim;
626}
627
628void OptimizableGraph::setRenamedTypesFromString(const std::string& types) {
629 Factory* factory = Factory::instance();
630 vector<string> typesMap = strSplit(types, ",");
631 for (size_t i = 0; i < typesMap.size(); ++i) {
632 vector<string> m = strSplit(typesMap[i], "=");
633 if (m.size() != 2) {
634 G2O_ERROR("{}: unable to extract type map from {}", __PRETTY_FUNCTION__,
635 typesMap[i]);
636 continue;
637 }
638 string typeInFile = trim(m[0]);
639 string loadedType = trim(m[1]);
640 if (!factory->knowsTag(loadedType)) {
641 G2O_ERROR("{}: unknown type {}", __PRETTY_FUNCTION__, loadedType);
642 continue;
643 }
644
645 _renamedTypesLookup[typeInFile] = loadedType;
646 }
647
648 G2O_DEBUG("Load look up table:");
649 for (std::map<std::string, std::string>::const_iterator it =
650 _renamedTypesLookup.begin();
651 it != _renamedTypesLookup.end(); ++it) {
652 G2O_DEBUG("{} -> {}", it->first, it->second);
653 }
654}
655
657 const OptimizationAlgorithmProperty& solverProperty,
658 const std::set<int>& vertDims_) const {
659 std::set<int> auxDims;
660 if (vertDims_.size() == 0) {
661 auxDims = dimensions();
662 }
663 const set<int>& vertDims = vertDims_.size() == 0 ? auxDims : vertDims_;
664 bool suitableSolver = true;
665 if (vertDims.size() == 2) {
666 if (solverProperty.requiresMarginalize) {
667 suitableSolver = vertDims.count(solverProperty.poseDim) == 1 &&
668 vertDims.count(solverProperty.landmarkDim) == 1;
669 } else {
670 suitableSolver = solverProperty.poseDim == -1;
671 }
672 } else if (vertDims.size() == 1) {
673 suitableSolver = vertDims.count(solverProperty.poseDim) == 1 ||
674 solverProperty.poseDim == -1;
675 } else {
676 suitableSolver =
677 solverProperty.poseDim == -1 && !solverProperty.requiresMarginalize;
678 }
679 return suitableSolver;
680}
681
682std::set<int> OptimizableGraph::dimensions() const {
683 std::set<int> auxDims;
684 for (VertexIDMap::const_iterator it = vertices().begin();
685 it != vertices().end(); ++it) {
687 static_cast<OptimizableGraph::Vertex*>(it->second);
688 auxDims.insert(v->dimension());
689 }
690 return auxDims;
691}
692
694 if (actions.size() > 0) {
696 for (HyperGraphActionSet::iterator it = actions.begin();
697 it != actions.end(); ++it) {
698 (*(*it))(this, &params);
699 }
700 }
701}
702
706
710
712 std::pair<HyperGraphActionSet::iterator, bool> insertResult =
713 _graphActions[AT_POSTITERATION].insert(action);
714 return insertResult.second;
715}
716
718 std::pair<HyperGraphActionSet::iterator, bool> insertResult =
719 _graphActions[AT_PREITERATION].insert(action);
720 return insertResult.second;
721}
722
726
730
731bool OptimizableGraph::saveUserData(std::ostream& os,
732 HyperGraph::Data* d) const {
733 Factory* factory = Factory::instance();
734 while (d) { // write the data packet for the vertex
735 string tag = factory->tag(d);
736 if (tag.size() > 0) {
737 os << tag << " ";
738 d->write(os);
739 os << endl;
740 }
741 d = d->next();
742 }
743 return os.good();
744}
745
746bool OptimizableGraph::saveVertex(std::ostream& os,
747 OptimizableGraph::Vertex* v) const {
748 Factory* factory = Factory::instance();
749 string tag = factory->tag(v);
750 if (tag.size() > 0) {
751 os << tag << " " << v->id() << " ";
752 v->write(os);
753 os << endl;
754 saveUserData(os, v->userData());
755 if (v->fixed()) {
756 os << "FIX " << v->id() << endl;
757 }
758 return os.good();
759 }
760 return false;
761}
762
763bool OptimizableGraph::saveParameter(std::ostream& os, Parameter* p) const {
764 Factory* factory = Factory::instance();
765 string tag = factory->tag(p);
766 if (tag.size() > 0) {
767 os << tag << " " << p->id() << " ";
768 p->write(os);
769 os << endl;
770 }
771 return os.good();
772}
773
774bool OptimizableGraph::saveEdge(std::ostream& os,
775 OptimizableGraph::Edge* e) const {
776 Factory* factory = Factory::instance();
777 string tag = factory->tag(e);
778 if (tag.size() > 0) {
779 os << tag << " ";
780 for (vector<HyperGraph::Vertex*>::const_iterator it = e->vertices().begin();
781 it != e->vertices().end(); ++it) {
782 int vertexId = (*it) ? (*it)->id() : HyperGraph::UnassignedId;
783 os << vertexId << " ";
784 }
785 e->write(os);
786 os << endl;
787 saveUserData(os, e->userData());
788 return os.good();
789 }
790 return false;
791}
792
797
799 bool allEdgeOk = true;
800 Eigen::SelfAdjointEigenSolver<MatrixX> eigenSolver;
801 for (OptimizableGraph::EdgeSet::const_iterator it = edges().begin();
802 it != edges().end(); ++it) {
803 OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
804 MatrixX::MapType information(e->informationData(), e->dimension(),
805 e->dimension());
806 // test on symmetry
807 bool isSymmetric = information.transpose() == information;
808 bool okay = isSymmetric;
809 if (isSymmetric) {
810 // compute the eigenvalues
811 eigenSolver.compute(information, Eigen::EigenvaluesOnly);
812 bool isSPD = eigenSolver.eigenvalues()(0) >= 0.;
813 okay = okay && isSPD;
814 }
815 allEdgeOk = allEdgeOk && okay;
816 if (!okay) {
817 if (verbose) {
818 vector<int> ids(e->vertices().size());
819 for (size_t i = 0; i < e->vertices().size(); ++i)
820 ids[i] = e->vertex(i)->id();
821 if (!isSymmetric)
822 G2O_WARN("Information Matrix for an edge is not symmetric: {}",
823 fmt::join(ids, " "));
824 else
825 G2O_WARN("Information Matrix for an edge is not SPD: {}",
826 fmt::join(ids, " "));
827 if (isSymmetric)
828 G2O_WARN("eigenvalues: {}", eigenSolver.eigenvalues().transpose());
829 }
830 }
831 }
832 return allEdgeOk;
833}
834
836#if (defined G2O_OPENMP) && EIGEN_VERSION_AT_LEAST(3, 1, 0)
837 Eigen::initParallel();
838#endif
839 return true;
840}
841
842} // namespace g2o
create vertices and edges based on TAGs in, for example, a file
Definition factory.h:48
bool knowsTag(const std::string &tag, int *elementType=0) const
Definition factory.cpp:152
static Factory * instance()
return the instance
Definition factory.cpp:46
HyperGraph::HyperGraphElement * construct(const std::string &tag) const
Definition factory.cpp:129
const std::string & tag(const HyperGraph::HyperGraphElement *v) const
return the TAG given a vertex
Definition factory.cpp:138
Abstract action that operates on an entire graph.
Container class that implements an interface for adding/removing Data elements in a linked list.
const Data * userData() const
the user data associated with this vertex
data packet for a vertex. Extend this class to store in the vertices the potential additional informa...
Definition hyper_graph.h:93
const Data * next() const
virtual bool write(std::ostream &os) const =0
write the data to a stream
int numUndefinedVertices() const
const VertexContainer & vertices() const
const Vertex * vertex(size_t i) const
abstract Vertex, your types must derive from that one
int id() const
returns the id
virtual bool addEdge(Edge *e)
virtual bool setEdgeVertex(Edge *e, int pos, Vertex *v)
std::set< Edge * > EdgeSet
virtual void clear()
clears the graph and empties all structures.
std::set< Vertex * > VertexSet
std::bitset< HyperGraph::HGET_NUM_ELEMS > GraphElemBitset
Definition hyper_graph.h:70
virtual bool addVertex(Vertex *v)
VertexIDMap _vertices
const EdgeSet & edges() const
static const int UnassignedId
Definition hyper_graph.h:67
const VertexIDMap & vertices() const
class G2O_CORE_API Data
Definition hyper_graph.h:72
void updateSize(const HyperGraph::Edge *e, bool reset)
int dimension() const
returns the dimensions of the error function
virtual double chi2() const =0
int level() const
returns the level of the edge
virtual int measurementDimension() const
void setRobustKernel(RobustKernel *ptr)
virtual bool write(std::ostream &os) const =0
write the vertex to a stream
virtual bool getMeasurementData(double *m) const
virtual const double * informationData() const =0
bool setParameterId(int argNum, int paramId)
virtual bool setMeasurementData(const double *m)
A general case Vertex for optimization.
virtual bool write(std::ostream &os) const =0
write the vertex to a stream
bool setMinimalEstimateData(const double *estimate)
virtual bool getEstimateData(double *estimate) const
int dimension() const
dimension of the estimated state belonging to this node
bool fixed() const
true => this node is fixed during the optimization
virtual void push()=0
backup the position of the vertex to a stack
virtual bool getMinimalEstimateData(double *estimate) const
bool setEstimateData(const double *estimate)
const OptimizableGraph * graph() const
virtual int minimalEstimateDimension() const
virtual int estimateDimension() const
void setFixed(bool fixed)
true => this node should be considered fixed during the optimization
virtual bool write(std::ostream &os) const
write the data to a stream
bool addParameter(Parameter *p)
add parameter to the container
virtual bool write(std::ostream &os) const =0
write the data to a stream
int id() const
Definition parameter.h:44
base for all robust cost functions
SlamParser::Parser::token token
if(!(yy_init))
#define G2O_ERROR(...)
Definition logger.h:89
#define G2O_WARN(...)
Definition logger.h:88
#define G2O_DEBUG(...)
Definition logger.h:90
#define __PRETTY_FUNCTION__
Definition macros.h:90
some general case utility functions
std::string trim(const std::string &s)
int readLine(std::istream &is, std::stringstream &currentLine)
void release(T *obj)
Definition ownership.h:8
std::vector< std::string > strSplit(const std::string &str, const std::string &delimiters)
Definition jet.h:876
virtual void setFixed(HyperGraph::VertexSet &vset, bool fixed)
fixes/releases a set of vertices
virtual bool setEdgeVertex(HyperGraph::Edge *e, int pos, HyperGraph::Vertex *v)
bool saveParameter(std::ostream &os, Parameter *v) const
JacobianWorkspace _jacobianWorkspace
bool removePostIterationAction(HyperGraphAction *action)
remove an action that should no longer be executed after each iteration
bool saveVertex(std::ostream &os, Vertex *v) const
bool verifyInformationMatrices(bool verbose=false) const
bool removePreIterationAction(HyperGraphAction *action)
remove an action that should no longer be executed before each iteration
bool addPreIterationAction(HyperGraphAction *action)
add an action to be executed before each iteration
bool saveEdge(std::ostream &os, Edge *e) const
std::set< int > dimensions() const
ParameterContainer _parameters
virtual void push()
push the estimate of all variables onto a stack
class G2O_CORE_API Edge
bool isSolverSuitable(const OptimizationAlgorithmProperty &solverProperty, const std::set< int > &vertDims=std::set< int >()) const
std::vector< HyperGraphActionSet > _graphActions
virtual bool addEdge(HyperGraph::Edge *e)
bool addPostIterationAction(HyperGraphAction *action)
add an action to be executed after each iteration
std::map< std::string, std::string > _renamedTypesLookup
virtual void pop()
pop (restore) the estimate of all variables from the stack
void performActions(int iter, HyperGraphActionSet &actions)
std::set< HyperGraphAction * > HyperGraphActionSet
void forEachVertex(std::function< void(OptimizableGraph::Vertex *)> fn)
apply a unary function to all vertices
virtual bool save(std::ostream &os, int level=0) const
save the graph to a stream. Again uses the Factory system.
virtual int optimize(int iterations, bool online=false)
virtual void postIteration(int)
OptimizableGraph()
empty constructor
virtual void preIteration(int)
bool saveSubset(std::ostream &os, HyperGraph::VertexSet &vset, int level=0)
save a subgraph to a stream. Again uses the Factory system.
virtual bool addVertex(HyperGraph::Vertex *v, Data *userData)
class G2O_CORE_API Vertex
bool saveUserData(std::ostream &os, HyperGraph::Data *v) const
virtual bool load(std::istream &is)
int maxDimension() const
return the maximum dimension of all vertices in the graph
double chi2() const
returns the chi2 of the current configuration
Vertex * vertex(int id)
returns the vertex number id appropriately casted
void setRenamedTypesFromString(const std::string &types)
int poseDim
dimension of the pose vertices (-1 if variable)
int landmarkDim
dimension of the landmark vertices (-1 if variable)