68 return _cacheContainer;
72 if (_cacheContainer) {
73 _cacheContainer->setUpdateNeeded();
74 _cacheContainer->update();
79 delete _cacheContainer;
84 bool ret = setEstimateDataImpl(v);
94 bool ret = setMinimalEstimateDataImpl(v);
106 :
HyperGraph::
Edge(), _dimension(-1), _level(0), _robustKernel(nullptr) {}
113 if (!v)
return nullptr;
121 if (!v)
return nullptr;
126 if ((
int)
_parameters.size() <= argNum)
return false;
127 if (argNum < 0)
return false;
129 _parameterIds[argNum] = paramId;
139 assert(
_parameters.size() == _parameterIds.size());
141 int index = _parameterIds[i];
144 if (
typeid(aux).name() != _parameterTypes[i]) {
146 "{}: FATAL, parameter type mismatch - encountered {}; should be {}",
158 if (_robustKernel)
release(_robustKernel);
186 "{}: FATAL, a vertex with (negative) ID {} cannot be inserted into the "
189 assert(0 &&
"Invalid vertex id");
195 "{}: a vertex with ID {} has already been registered with this "
202 "{}: FATAL, vertex with ID {} has already been registered with another "
214 assert(ov &&
"Vertex does not inherit from OptimizableGraph::Vertex");
215 if (!ov)
return false;
223 if (g !=
nullptr && g !=
this) {
225 "{}: FATAL, edge with ID {} has already registered with another graph "
232 if (!eresult)
return false;
237 G2O_ERROR(
"{}: FATAL, cannot resolve parameters for edge {}",
238 static_cast<void*
>(e));
242 G2O_ERROR(
"{}: FATAL, cannot resolve caches for edge {}",
243 static_cast<void*
>(e));
254 assert(e &&
"Edge does not inherit from OptimizableGraph::Edge");
255 if (!e)
return false;
267 assert(ee &&
"Edge is not a OptimizableGraph::Edge");
272 G2O_ERROR(
"{}: FATAL, cannot resolve parameters for edge {}",
273 static_cast<void*
>(e));
277 G2O_ERROR(
"{}: FATAL, cannot resolve caches for edge {}",
278 static_cast<void*
>(e));
292 for (OptimizableGraph::EdgeSet::const_iterator it = this->
edges().begin();
293 it != this->
edges().end(); ++it) {
342 for (
auto it = vset.begin(); it != vset.end(); ++it) {
349 set<string> warnedUnknownTypes;
350 stringstream currentLine;
355 elemBitset[HyperGraph::HGET_PARAMETER] = 1;
359 elemParamBitset[HyperGraph::HGET_PARAMETER] = 1;
362 Data* previousData = 0;
366 int bytesRead =
readLine(is, currentLine);
368 if (bytesRead == -1)
break;
369 currentLine >>
token;
370 if (bytesRead == 0 ||
token.size() == 0 ||
token[0] ==
'#')
continue;
373 if (
token ==
"FIX") {
375 while (currentLine >>
id) {
384 G2O_WARN(
"Unable to fix vertex with id {}. Not found in the graph.",
393 map<string, string>::const_iterator foundIt =
396 token = foundIt->second;
401 if (warnedUnknownTypes.count(
token) != 1) {
402 warnedUnknownTypes.insert(
token);
409 HyperGraph::HyperGraphElement* pelement =
412 assert(pelement->elementType() == HyperGraph::HGET_PARAMETER &&
413 "Should be a param");
414 Parameter* p =
static_cast<Parameter*
>(pelement);
418 bool r = p->read(currentLine);
420 G2O_ERROR(
"{}: reading data {} for parameter {} at line ",
426 "{}: Parameter of type: {} id: {} already defined at line {}",
433 HyperGraph::HyperGraphElement* element =
435 if (
dynamic_cast<Vertex*
>(element)) {
440 bool r = v->read(currentLine);
442 G2O_ERROR(
"{}: Error reading vertex {} {} at line {}",
446 G2O_ERROR(
"{}: Failure adding Vertex {} {} at line {}",
450 previousDataContainer = v;
452 }
else if (
dynamic_cast<Edge*
>(element)) {
454 Edge* e =
static_cast<Edge*
>(element);
455 int numV = e->vertices().size();
458 if (e->vertices().size() != 0) {
459 ids.resize(e->vertices().size());
460 for (
int l = 0; l < numV; ++l) currentLine >> ids[l];
463 while (currentLine >> buff) {
464 if (buff ==
"||")
break;
465 ids.push_back(atoi(buff.c_str()));
470 bool vertsOkay =
true;
471 for (
size_t l = 0; l < ids.size(); ++l) {
472 int vertexId = ids[l];
474 HyperGraph::Vertex* v =
vertex(vertexId);
483 G2O_ERROR(
"{}: Unable to find vertices for edge {} at line {} IDs: {}",
488 bool r = e->read(currentLine);
490 G2O_ERROR(
"{}: Unable to add edge {} at line {} IDs: {}",
492 fmt::join(ids,
" "));
498 previousDataContainer = e;
499 }
else if (
dynamic_cast<Data*
>(
501 Data* d =
static_cast<Data*
>(element);
502 bool r = d->read(currentLine);
508 }
else if (previousData) {
509 previousData->setNext(d);
510 d->setDataContainer(previousData->dataContainer());
512 }
else if (previousDataContainer) {
514 d->setDataContainer(previousDataContainer);
516 previousDataContainer = 0;
518 G2O_ERROR(
"{}: got data element, but no data container available",
534 ifstream ifs(filename);
536 G2O_ERROR(
"Unable to open file {}", filename);
543 ofstream ofs(filename);
544 if (!ofs)
return false;
545 return save(ofs, level);
551 set<Vertex*, VertexIDCompare> verticesToSave;
552 for (HyperGraph::EdgeSet::const_iterator it =
edges().begin();
553 it !=
edges().end(); ++it) {
555 if (e->
level() == level) {
563 for (
auto v : verticesToSave)
saveVertex(os, v);
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);
572 sort(edgesToSave.begin(), edgesToSave.end(), EdgeIDCompare());
573 for (
auto e : edgesToSave)
saveEdge(os, static_cast<
Edge*>(e));
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;
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;
597 if (!verticesInEdge)
continue;
610 if (v) vset.insert(v);
613 for (
auto e : eset)
saveEdge(os, static_cast<
Edge*>(e));
619 for (HyperGraph::VertexIDMap::const_iterator it =
vertices().begin();
623 maxDim = (std::max)(maxDim, v->
dimension());
630 vector<string> typesMap =
strSplit(types,
",");
631 for (
size_t i = 0; i < typesMap.size(); ++i) {
632 vector<string> m =
strSplit(typesMap[i],
"=");
638 string typeInFile =
trim(m[0]);
639 string loadedType =
trim(m[1]);
640 if (!factory->
knowsTag(loadedType)) {
649 for (std::map<std::string, std::string>::const_iterator it =
652 G2O_DEBUG(
"{} -> {}", it->first, it->second);
658 const std::set<int>& vertDims_)
const {
659 std::set<int> auxDims;
660 if (vertDims_.size() == 0) {
663 const set<int>& vertDims = vertDims_.size() == 0 ? auxDims : vertDims_;
664 bool suitableSolver =
true;
665 if (vertDims.size() == 2) {
667 suitableSolver = vertDims.count(solverProperty.
poseDim) == 1 &&
670 suitableSolver = solverProperty.
poseDim == -1;
672 }
else if (vertDims.size() == 1) {
673 suitableSolver = vertDims.count(solverProperty.
poseDim) == 1 ||
679 return suitableSolver;
683 std::set<int> auxDims;
684 for (VertexIDMap::const_iterator it =
vertices().begin();
694 if (actions.size() > 0) {
696 for (HyperGraphActionSet::iterator it = actions.begin();
697 it != actions.end(); ++it) {
698 (*(*it))(
this, ¶ms);
712 std::pair<HyperGraphActionSet::iterator, bool> insertResult =
714 return insertResult.second;
718 std::pair<HyperGraphActionSet::iterator, bool> insertResult =
720 return insertResult.second;
735 string tag = factory->
tag(d);
736 if (tag.size() > 0) {
749 string tag = factory->
tag(v);
750 if (tag.size() > 0) {
751 os << tag <<
" " << v->
id() <<
" ";
756 os <<
"FIX " << v->
id() << endl;
765 string tag = factory->
tag(p);
766 if (tag.size() > 0) {
767 os << tag <<
" " << p->
id() <<
" ";
777 string tag = factory->
tag(e);
778 if (tag.size() > 0) {
780 for (vector<HyperGraph::Vertex*>::const_iterator it = e->
vertices().begin();
783 os << vertexId <<
" ";
799 bool allEdgeOk =
true;
800 Eigen::SelfAdjointEigenSolver<MatrixX> eigenSolver;
801 for (OptimizableGraph::EdgeSet::const_iterator it =
edges().begin();
802 it !=
edges().end(); ++it) {
807 bool isSymmetric = information.transpose() == information;
808 bool okay = isSymmetric;
811 eigenSolver.compute(information, Eigen::EigenvaluesOnly);
812 bool isSPD = eigenSolver.eigenvalues()(0) >= 0.;
813 okay = okay && isSPD;
815 allEdgeOk = allEdgeOk && okay;
818 vector<int> ids(e->
vertices().size());
819 for (
size_t i = 0; i < e->
vertices().size(); ++i)
822 G2O_WARN(
"Information Matrix for an edge is not symmetric: {}",
823 fmt::join(ids,
" "));
825 G2O_WARN(
"Information Matrix for an edge is not SPD: {}",
826 fmt::join(ids,
" "));
828 G2O_WARN(
"eigenvalues: {}", eigenSolver.eigenvalues().transpose());
836#if (defined G2O_OPENMP) && EIGEN_VERSION_AT_LEAST(3, 1, 0)
837 Eigen::initParallel();
create vertices and edges based on TAGs in, for example, a file
bool knowsTag(const std::string &tag, int *elementType=0) const
static Factory * instance()
return the instance
HyperGraph::HyperGraphElement * construct(const std::string &tag) const
const std::string & tag(const HyperGraph::HyperGraphElement *v) const
return the TAG given a vertex
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
void setUserData(Data *obs)
data packet for a vertex. Extend this class to store in the vertices the potential additional informa...
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
virtual bool addVertex(Vertex *v)
const EdgeSet & edges() const
static const int UnassignedId
const VertexIDMap & vertices() const
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 bool setMeasurementFromState()
virtual int measurementDimension() const
OptimizableGraph * graph()
void setRobustKernel(RobustKernel *ptr)
virtual bool write(std::ostream &os) const =0
write the vertex to a stream
virtual bool resolveCaches()
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)
OptimizableGraph * _graph
virtual bool getEstimateData(double *estimate) const
int dimension() const
dimension of the estimated state belonging to this node
virtual void discardTop()=0
bool fixed() const
true => this node is fixed during the optimization
virtual void push()=0
backup the position of the vertex to a stack
CacheContainer * cacheContainer()
virtual void updateCache()
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
base for all robust cost functions
SlamParser::Parser::token token
#define __PRETTY_FUNCTION__
some general case utility functions
std::string trim(const std::string &s)
int readLine(std::istream &is, std::stringstream ¤tLine)
std::vector< std::string > strSplit(const std::string &str, const std::string &delimiters)
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
virtual void clearParameters()
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
virtual void discardTop()
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
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)
virtual ~OptimizableGraph()
std::set< HyperGraphAction * > HyperGraphActionSet
void forEachVertex(std::function< void(OptimizableGraph::Vertex *)> fn)
apply a unary function to all vertices
static bool initMultiThreading()
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)
describe the properties of a solver
int poseDim
dimension of the pose vertices (-1 if variable)
int landmarkDim
dimension of the landmark vertices (-1 if variable)