44 #include "g2o/config.h" 51 _forceStopFlag(0), _verbose(false), _algorithm(0), _computeBatchStatistics(false)
65 if (actions.size() > 0) {
66 for (HyperGraphActionSet::iterator it = actions.begin(); it != actions.end(); ++it)
71 # pragma omp parallel for default (shared) if (_activeEdges.size() > 50) 73 for (
int k = 0; k < static_cast<int>(
_activeEdges.size()); ++k) {
79 for (
int k = 0; k < static_cast<int>(
_activeEdges.size()); ++k) {
83 cerr <<
"computeActiveErrors(): found NaN in error for edge " << e << endl;
121 for (HyperGraph::VertexIDMap::iterator it=
vertices().begin(); it!=
vertices().end(); ++it){
127 for (HyperGraph::VertexIDMap::iterator it=
vertices().begin(); it!=
vertices().end(); ++it){
143 for (HyperGraph::VertexIDMap::iterator it=
vertices().begin(); it!=
vertices().end(); ++it){
145 maxDim = std::max(maxDim,v->
dimension());
148 for (HyperGraph::VertexIDMap::iterator it=
vertices().begin(); it!=
vertices().end(); ++it){
156 for (HyperGraph::EdgeSet::const_iterator eit = v->
edges().begin(); eit != v->
edges().end(); ++eit) {
172 _ivMap.resize(vlist.size());
174 for (
int k=0; k<2; k++)
175 for (VertexContainer::iterator it=vlist.begin(); it!=vlist.end(); ++it){
193 for (
size_t i=0; i<
_ivMap.size(); ++i){
194 _ivMap[i]->setHessianIndex(-1);
201 for (VertexIDMap::iterator it=
vertices().begin(); it!=
vertices().end(); ++it)
202 vset.insert(it->second);
207 if (
edges().size() == 0) {
213 assert(workspaceAllocated &&
"Error while allocating memory for the Jacobians");
218 set<Edge*> auxEdgeSet;
219 for (HyperGraph::VertexSet::iterator it=vset.begin(); it!=vset.end(); ++it){
224 for (OptimizableGraph::EdgeSet::const_iterator it=vEdges.begin(); it!=vEdges.end(); ++it){
226 if (level < 0 || e->level() == level) {
228 bool allVerticesOK =
true;
229 for (vector<HyperGraph::Vertex*>::const_iterator vit = e->
vertices().begin(); vit != e->
vertices().end(); ++vit) {
230 if (vset.find(*vit) == vset.end()) {
231 allVerticesOK =
false;
236 auxEdgeSet.insert(e);
248 if (estimateDim > 0) {
252 bool hasNan =
arrayHasNaN(estimateData.data(), estimateDim, &k);
254 cerr <<
__PRETTY_FUNCTION__ <<
": Vertex " << v->
id() <<
" contains a nan entry at index " << k << endl;
263 for (set<Edge*>::iterator it = auxEdgeSet.begin(); it != auxEdgeSet.end(); ++it)
269 return indexMappingStatus;
275 assert(workspaceAllocated &&
"Error while allocating memory for the Jacobians");
280 set<Vertex*> auxVertexSet;
281 for (HyperGraph::EdgeSet::iterator it=eset.begin(); it!=eset.end(); ++it){
285 for (vector<HyperGraph::Vertex*>::const_iterator vit = e->
vertices().begin(); vit != e->
vertices().end(); ++vit) {
286 auxVertexSet.insert(static_cast<OptimizableGraph::Vertex*>(*vit));
288 _activeEdges.push_back(reinterpret_cast<OptimizableGraph::Edge*>(*it));
292 for (set<Vertex*>::iterator it = auxVertexSet.begin(); it != auxVertexSet.end(); ++it)
298 return indexMappingStatus;
302 for (VertexIDMap::iterator it=
vertices().begin(); it!=
vertices().end(); ++it) {
317 std::set<Vertex*> backupVertices;
321 for (
size_t i = 0; i < e->
vertices().size(); ++i) {
326 fixedVertices.insert(v);
328 for (EdgeSet::const_iterator vedgeIt = v->
edges().begin(); vedgeIt != v->
edges().end(); ++vedgeIt) {
333 fixedVertices.insert(v);
338 std::set<Vertex*>::const_iterator foundIt = backupVertices.find(v);
339 if (foundIt == backupVertices.end()) {
341 backupVertices.insert(v);
348 estimatePropagator.
propagate(fixedVertices, costFunction);
351 for (std::set<Vertex*>::iterator it = backupVertices.begin(); it != backupVertices.end(); ++it) {
357 cerr <<
"iteration= -1\t chi2= " <<
activeChi2()
360 <<
"\t (using initial guess from " << costFunction.
name() <<
")" << endl;
367 cerr <<
__PRETTY_FUNCTION__ <<
": 0 vertices to optimize, maybe forgot to call initializeOptimization()" << endl;
386 for (
int i=0; i<iterations && !
terminate() && ok; i++){
401 bool errorComputed =
false;
404 errorComputed =
true;
414 cerr <<
"iteration= " << i
416 <<
"\t time= " << dts
417 <<
"\t cumTime= " << cumTime
425 if (result == OptimizationAlgorithm::Fail) {
431 void SparseOptimizer::update(
const double* update)
434 for (
size_t i=0; i <
_ivMap.size(); ++i) {
457 std::vector<HyperGraph::Vertex*> newVertices;
458 newVertices.reserve(vset.size());
461 for (HyperGraph::EdgeSet::iterator it = eset.begin(); it != eset.end(); ++it) {
467 size_t next =
_ivMap.size();
468 for (HyperGraph::VertexSet::iterator it = vset.begin(); it != vset.end(); ++it) {
474 newVertices.push_back(v);
527 for (VertexContainer::iterator it = vlist.begin(); it != vlist.end(); ++it)
533 for (VertexContainer::iterator it = vlist.begin(); it != vlist.end(); ++it)
539 for (HyperGraph::VertexSet::iterator it = vlist.begin(); it != vlist.end(); ++it) {
544 cerr << __FUNCTION__ <<
": FATAL PUSH SET" << endl;
550 for (HyperGraph::VertexSet::iterator it = vlist.begin(); it != vlist.end(); ++it){
555 cerr << __FUNCTION__ <<
": FATAL POP SET" << endl;
561 for (VertexContainer::iterator it = vlist.begin(); it != vlist.end(); ++it)
601 return insertResult.second;
virtual void printVerbose(std::ostream &os) const
virtual bool updateInitialization(HyperGraph::VertexSet &vset, HyperGraph::EdgeSet &eset)
virtual void computeInitialGuess()
double get_monotonic_time()
virtual SolverResult solve(int iteration, bool online=false)=0
int id() const
returns the id
statistics about the optimization
const Vertex * vertex(size_t i) const
bool terminate()
if external stop flag is given, return its state. False otherwise
#define __PRETTY_FUNCTION__
void setHessianIndex(int ti)
set the temporary index of the vertex in the parameter blocks
int numVertices
how many vertices are involved
virtual bool getEstimateData(double *estimate) const
some general case utility functions
VertexContainer _activeVertices
sorted according to VertexIDCompare
virtual bool removeVertex(Vertex *v, bool detach=false)
removes a vertex from the graph. Returns true on success (vertex was present)
virtual const double * errorData() const =0
returns the error vector cached after calling the computeError;
Eigen::Matrix< double, 3, 1, Eigen::ColMajor > Vector3D
int dimension() const
returns the dimensions of the error function
virtual ~SparseOptimizer()
std::vector< Vertex * > VertexContainer
void setComputeBatchStatistics(bool computeBatchStatistics)
virtual bool updateStructure(const std::vector< HyperGraph::Vertex * > &vset, const HyperGraph::EdgeSet &edges)=0
bool removeComputeErrorAction(HyperGraphAction *action)
remove an action that should no longer be execured before computing the error vectors ...
virtual bool allVerticesFixed() const =0
std::set< Vertex * > VertexSet
virtual double chi2() const =0
computes the chi2 based on the cached error value, only valid after computeError has been called...
propagation of an initial guess
int optimize(int iterations, bool online=false)
virtual bool init(bool online=false)=0
virtual double initialEstimatePossible(const OptimizableGraph::VertexSet &from, OptimizableGraph::Vertex *to)
int hessianIndex() const
temporary index of this node in the parameter vector obtained from linearization
int iteration
which iteration
void computeActiveErrors()
virtual void setToOrigin()
virtual void robustify(double squaredError, Vector3D &rho) const =0
virtual void postIteration(int)
called at the end of an iteration (argument is the number of the iteration)
const VertexIDMap & vertices() const
bool arrayHasNaN(const double *array, int size, int *nanIndex=0)
utility functions for handling time related stuff
void oplus(const double *v)
std::set< Edge * > EdgeSet
virtual Vertex * findGauge()
finds a gauge in the graph to remove the undefined dof.
int dimension() const
dimension of the estimated state belonging to this node
int numUndefinedVertices() const
const VertexContainer & vertices() const
const EdgeSet & edges() const
returns the set of hyper-edges that are leaving/entering in this vertex
void setVerbose(bool verbose)
virtual int estimateDimension() const
RobustKernel * robustKernel() const
if NOT NULL, error of this edge will be robustifed with the kernel
virtual void initialEstimate(const OptimizableGraph::VertexSet &from, OptimizableGraph::Vertex *to)=0
const EdgeSet & edges() const
VertexContainer::const_iterator findActiveVertex(const OptimizableGraph::Vertex *v) const
void setForceStopFlag(bool *flag)
virtual void computeError()=0
void setAlgorithm(OptimizationAlgorithm *algorithm)
int numEdges
how many edges
BatchStatisticsContainer _batchStatistics
global statistics of the optimizer, e.g., timing, num-non-zeros
void push()
push all the active vertices onto a stack
void setOptimizer(SparseOptimizer *optimizer)
virtual void push()=0
backup the position of the vertex to a stack
EdgeContainer _activeEdges
sorted according to EdgeIDCompare
virtual const char * name() const
void propagate(OptimizableGraph::Vertex *v, const EstimatePropagator::PropagateCost &cost, const EstimatePropagator::PropagateAction &action=PropagateAction(), double maxDistance=std::numeric_limits< double >::max(), double maxEdgeCost=std::numeric_limits< double >::max())
cost for traversing along active edges in the optimizer
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
order vertices based on their ID
bool buildIndexMapping(SparseOptimizer::VertexContainer &vlist)
void pop()
pop (restore) the estimate of the active vertices from the stack
Protocol The SLAM executable accepts actions
void sortVectorContainers()
bool _computeBatchStatistics
bool marginalized() const
true => this node is marginalized out during the optimization
order edges based on the internal ID, which is assigned to the edge in addEdge()
A general case Vertex for optimization.
bool addComputeErrorAction(HyperGraphAction *action)
add an action to be executed before the error vectors are computed
abstract Vertex, your types must derive from that one
Eigen::Matrix< double, Eigen::Dynamic, 1, Eigen::ColMajor > VectorXD
void setToOrigin()
sets the node to the origin (used in the multilevel stuff)
bool computeBatchStatistics() const
EdgeContainer::const_iterator findActiveEdge(const OptimizableGraph::Edge *e) const
JacobianWorkspace _jacobianWorkspace
double activeRobustChi2() const
virtual void preIteration(int)
called at the beginning of an iteration (argument is the number of the iteration) ...
virtual bool removeVertex(HyperGraph::Vertex *v, bool detach=false)
bool fixed() const
true => this node is fixed during the optimization
void discardTop()
same as above, but for the active vertices
std::set< HyperGraphAction * > HyperGraphActionSet
virtual bool initializeOptimization(HyperGraph::EdgeSet &eset)
Generic interface for a non-linear solver operating on a graph.
std::vector< HyperGraphActionSet > _graphActions
bool computeMarginals(SparseBlockMatrix< MatrixXD > &spinv, const std::vector< std::pair< int, int > > &blockIndices)
bool verbose() const
verbose information during optimization
const OptimizationAlgorithm * algorithm() const
the solver used by the optimizer
Sparse matrix which uses blocks.
static void setGlobalStats(G2OBatchStatistics *b)
OptimizationAlgorithm * _algorithm
Abstract action that operates on an entire graph.
virtual bool computeMarginals(SparseBlockMatrix< MatrixXD > &spinv, const std::vector< std::pair< int, int > > &blockIndices)=0
double activeChi2() const