35 #include <Eigen/Dense> 55 _graph(0), _userData(0), _hessianIndex(-1), _fixed(false), _marginalized(false),
56 _colInHessian(-1), _cacheContainer(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");
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");
245 assert(ov &&
"Vertex does not inherit from OptimizableGraph::Vertex");
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");
260 assert(e &&
"Edge does not inherit from OptimizableGraph::Edge");
273 cerr << __FUNCTION__ <<
": FATAL, cannot resolve parameters for edge " << e << endl;
278 cerr << __FUNCTION__ <<
": FATAL, cannot resolve caches for edge " << e << endl;
296 assert(ee &&
"Edge is not a OptimizableGraph::Edge");
301 cerr << __FUNCTION__ <<
": FATAL, cannot resolve parameters for edge " << e << endl;
305 cerr << __FUNCTION__ <<
": FATAL, cannot resolve caches for edge " << e << endl;
318 for (OptimizableGraph::EdgeSet::const_iterator it = this->
edges().begin(); it != this->
edges().end(); ++it) {
327 for (OptimizableGraph::VertexIDMap::iterator it=
_vertices.begin(); it!=
_vertices.end(); ++it) {
335 for (OptimizableGraph::VertexIDMap::iterator it=
_vertices.begin(); it!=
_vertices.end(); ++it) {
343 for (OptimizableGraph::VertexIDMap::iterator it=
_vertices.begin(); it!=
_vertices.end(); ++it) {
351 for (HyperGraph::VertexSet::iterator it=vset.begin(); it!=vset.end(); ++it) {
359 for (HyperGraph::VertexSet::iterator it=vset.begin(); it!=vset.end(); ++it) {
367 for (HyperGraph::VertexSet::iterator it=vset.begin(); it!=vset.end(); ++it) {
375 for (HyperGraph::VertexSet::iterator it=vset.begin(); it!=vset.end(); ++it) {
388 cerr <<
"Loaded " <<
_parameters.size() <<
" parameters" << endl;
391 is.seekg(ios_base::beg);
392 set<string> warnedUnknownTypes;
393 stringstream currentLine;
402 Data* previousData = 0;
406 int bytesRead =
readLine(is, currentLine);
410 currentLine >>
token;
412 if (bytesRead == 0 || token.size() == 0 || token[0] ==
'#')
416 bool handledCommand =
false;
418 if (token ==
"FIX") {
419 handledCommand =
true;
421 while (currentLine >>
id) {
425 cerr <<
"Fixing vertex " << v->
id() << endl;
429 cerr <<
"Warning: Unable to fix vertex with id " <<
id <<
". Not found in the graph." << endl;
441 token = foundIt->second;
446 if (warnedUnknownTypes.count(token) != 1) {
447 warnedUnknownTypes.insert(token);
454 if (dynamic_cast<Vertex*>(element)) {
460 bool r = v->
read(currentLine);
468 previousDataContainer = v;
471 else if (dynamic_cast<Edge*>(element)) {
474 Edge* e =
static_cast<Edge*
>(element);
484 currentLine >> id1 >> id2;
490 if (! from && id1 >=0) {
496 if (! to && id2 >=0) {
505 if ( (!from && id1>=0) ){
506 cerr <<
__PRETTY_FUNCTION__ <<
": Unable to find vertex for edge " << token <<
" " << id1 <<
" <-> " << id2 << endl;
510 if (! to && id2>=0 ){
511 cerr <<
__PRETTY_FUNCTION__ <<
": Unable to find vertex for edge " << token <<
" " << id1 <<
" <-> " << id2 << endl;
519 e->
read(currentLine);
521 cerr <<
__PRETTY_FUNCTION__ <<
": Unable to add edge " << token <<
" " << id1 <<
" <-> " << id2 << endl;
528 fromSet.insert(from);
548 for (
int l = 0; l < numV; ++l)
549 currentLine >> ids[l];
555 ids.push_back(atoi(buff.c_str()));
561 bool vertsOkay =
true;
562 for (
int l = 0; l < numV; ++l) {
576 for (
int l = 0; l < numV; ++l) {
579 cerr <<
" " << ids[l];
583 bool r = e->
read(currentLine);
586 for (
int l = 0; l < numV; ++l) {
589 cerr <<
" " << ids[l];
596 previousDataContainer = e;
597 }
else if (dynamic_cast<Data*>(element)) {
599 Data* d =
static_cast<Data*
>(element);
600 bool r = d->
read(currentLine);
602 cerr <<
__PRETTY_FUNCTION__ <<
": Error reading data " << token <<
" at line " << lineNumber << endl;
605 }
else if (previousData){
611 }
else if (previousDataContainer){
616 previousDataContainer = 0;
619 cerr <<
__PRETTY_FUNCTION__ <<
": got data element, but no data container available" << endl;
631 ifstream ifs(filename);
636 return load(ifs, createEdges);
641 ofstream ofs(filename);
644 return save(ofs, level);
651 set<Vertex*, VertexIDCompare> verticesToSave;
652 for (HyperGraph::EdgeSet::const_iterator it =
edges().begin(); it !=
edges().end(); ++it) {
655 for (vector<HyperGraph::Vertex*>::const_iterator it = e->
vertices().begin(); it != e->
vertices().end(); ++it) {
657 verticesToSave.insert(static_cast<OptimizableGraph::Vertex*>(*it));
662 for (set<Vertex*, VertexIDCompare>::const_iterator it = verticesToSave.begin(); it != verticesToSave.end(); ++it){
668 for (HyperGraph::EdgeSet::const_iterator it =
edges().begin(); it !=
edges().end(); ++it) {
671 edgesToSave.push_back(const_cast<Edge*>(e));
673 sort(edgesToSave.begin(), edgesToSave.end(),
EdgeIDCompare());
675 for (EdgeContainer::const_iterator it = edgesToSave.begin(); it != edgesToSave.end(); ++it) {
689 for (HyperGraph::VertexSet::const_iterator it=vset.begin(); it!=vset.end(); it++){
693 for (HyperGraph::EdgeSet::const_iterator it =
edges().begin(); it !=
edges().end(); ++it) {
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;
705 if (! verticesInEdge)
718 std::set<OptimizableGraph::Vertex*> vset;
719 for (HyperGraph::EdgeSet::const_iterator it = eset.begin(); it != eset.end(); ++it) {
721 for (vector<HyperGraph::Vertex*>::const_iterator it = e->
vertices().begin(); it != e->
vertices().end(); ++it) {
728 for (std::set<OptimizableGraph::Vertex*>::const_iterator it=vset.begin(); it!=vset.end(); ++it){
733 for (HyperGraph::EdgeSet::const_iterator it = eset.begin(); it != eset.end(); ++it) {
742 for (HyperGraph::VertexIDMap::iterator it=g->
vertices().begin(); it!=g->
vertices().end(); ++it){
751 for (HyperGraph::EdgeSet::iterator it=g->
edges().begin(); it!=g->
edges().end(); ++it){
756 for (vector<HyperGraph::Vertex*>::const_iterator it = e->
vertices().begin(); it != e->
vertices().end(); ++it) {
767 for (HyperGraph::VertexIDMap::const_iterator it=
vertices().begin(); it!=
vertices().end(); ++it){
769 maxDim = (std::max)(maxDim, v->
dimension());
777 vector<string> typesMap =
strSplit(types,
",");
778 for (
size_t i = 0; i < typesMap.size(); ++i) {
779 vector<string> m =
strSplit(typesMap[i],
"=");
781 cerr <<
__PRETTY_FUNCTION__ <<
": unable to extract type map from " << typesMap[i] << endl;
784 string typeInFile =
trim(m[0]);
785 string loadedType =
trim(m[1]);
786 if (! factory->
knowsTag(loadedType)) {
794 cerr <<
"# load look up table" << endl;
796 cerr <<
"#\t" << it->first <<
" -> " << it->second << endl;
802 std::set<int> auxDims;
803 if (vertDims_.size() == 0) {
806 const set<int>& vertDims = vertDims_.size() == 0 ? auxDims : vertDims_;
807 bool suitableSolver =
true;
808 if (vertDims.size() == 2) {
810 suitableSolver = vertDims.count(solverProperty.
poseDim) == 1 && vertDims.count(solverProperty.
landmarkDim) == 1;
813 suitableSolver = solverProperty.
poseDim == -1;
815 }
else if (vertDims.size() == 1) {
816 suitableSolver = vertDims.count(solverProperty.
poseDim) == 1 || solverProperty.
poseDim == -1;
820 return suitableSolver;
825 std::set<int> auxDims;
826 for (VertexIDMap::const_iterator it =
vertices().begin(); it !=
vertices().end(); ++it) {
836 if (actions.size() > 0) {
838 for (HyperGraphActionSet::iterator it = actions.begin(); it != actions.end(); ++it) {
839 (*(*it))(
this, ¶ms);
847 if (actions.size() > 0) {
849 for (HyperGraphActionSet::iterator it = actions.begin(); it != actions.end(); ++it) {
850 (*(*it))(
this, ¶ms);
858 return insertResult.second;
864 return insertResult.second;
880 string tag = factory->
tag(d);
881 if (tag.size() > 0) {
894 string tag = factory->
tag(v);
895 if (tag.size() > 0) {
896 os << tag <<
" " << v->
id() <<
" ";
901 os <<
"FIX " << v->
id() << endl;
911 string tag = factory->
tag(p);
912 if (tag.size() > 0) {
913 os << tag <<
" " << p->
id() <<
" ";
923 string tag = factory->
tag(e);
924 if (tag.size() > 0) {
927 os << e->
id() <<
" ";
928 for (vector<HyperGraph::Vertex*>::const_iterator it = e->
vertices().begin(); it != e->
vertices().end(); ++it) {
930 os << vertexId <<
" ";
948 bool allEdgeOk =
true;
949 Eigen::SelfAdjointEigenSolver<MatrixXD> eigenSolver;
950 for (OptimizableGraph::EdgeSet::const_iterator it =
edges().begin(); it !=
edges().end(); ++it) {
954 bool isSymmetric = information.transpose() == information;
955 bool okay = isSymmetric;
958 eigenSolver.compute(information, Eigen::EigenvaluesOnly);
959 bool isSPD = eigenSolver.eigenvalues()(0) >= 0.;
960 okay = okay && isSPD;
962 allEdgeOk = allEdgeOk && okay;
966 cerr <<
"Information Matrix for an edge is not symmetric:";
968 cerr <<
"Information Matrix for an edge is not SPD:";
969 for (
size_t i = 0; i < e->
vertices().size(); ++i)
972 cerr <<
"\teigenvalues: " << eigenSolver.eigenvalues().transpose();
982 # if (defined G2O_OPENMP) && EIGEN_VERSION_AT_LEAST(3,1,0) 983 Eigen::initParallel();
stuff to open files and other unsorted components ProjectiveCamera types
const Data * next() const
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
const Vertex * vertex(size_t i) const
#define __PRETTY_FUNCTION__
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
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...
bool saveParameter(std::ostream &os, Parameter *v) const
std::vector< std::string > _parameterTypes
const Data * userData() const
the user data associated with this vertex
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)
CacheContainer * _cacheContainer
bool removePreIterationAction(HyperGraphAction *action)
remove an action that should no longer be execured before each iteration
std::bitset< HyperGraph::HGET_NUM_ELEMS > GraphElemBitset
bool saveEdge(std::ostream &os, Edge *e) const
virtual void clearParameters()
std::set< Vertex * > VertexSet
HyperGraph::HyperGraphElement * construct(const std::string &tag) const
virtual double chi2() const =0
computes the chi2 based on the cached error value, only valid after computeError has been called...
CacheContainer * cacheContainer()
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
virtual void updateCache()
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)
virtual bool addEdge(Edge *e)
const VertexIDMap & vertices() const
virtual bool read(std::istream &is)=0
read the data from a stream
base for all robust cost functions
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)
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
int dimension() const
dimension of the estimated state belonging to this node
virtual ~OptimizableGraph()
int numUndefinedVertices() const
bool setParameterId(int argNum, int paramId)
const VertexContainer & vertices() const
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
const EdgeSet & edges() const
returns the set of hyper-edges that are leaving/entering in this vertex
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_)
virtual bool resolveCaches()
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
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
RobustKernel * _robustKernel
create vertices and edges based on TAGs in, for example, a file
virtual void push()=0
backup the position of the vertex to a stack
int readLine(std::istream &is, std::stringstream ¤tLine)
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
OptimizableGraph * graph()
bool knowsTag(const std::string &tag, int *elementType=0) const
std::map< std::string, std::string > _renamedTypesLookup
Protocol The SLAM executable accepts actions
DataContainer * dataContainer()
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
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)
void setNext(Data *next_)
virtual void resize(size_t size)
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
void setUserData(Data *obs)
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
Container class that implements an interface for adding/removing Data elements in a linked list...
virtual bool setMeasurementFromState()
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.
OptimizableGraph * _graph
VertexContainer _vertices