38#include "g2o/config.h"
56 _computeBatchStatistics(false) {
68 if (actions.size() > 0) {
69 for (HyperGraphActionSet::iterator it = actions.begin();
70 it != actions.end(); ++it)
75#pragma omp parallel for default(shared) if (_activeEdges.size() > 50)
77 for (
int k = 0; k < static_cast<int>(
_activeEdges.size()); ++k) {
83 for (
int k = 0; k < static_cast<int>(
_activeEdges.size()); ++k) {
87 G2O_WARN(
"computeActiveErrors(): found NaN in error for edge {}",
88 static_cast<void*
>(e));
96 for (EdgeContainer::const_iterator it =
_activeEdges.begin();
107 for (EdgeContainer::const_iterator it =
_activeEdges.begin();
120 if (
vertices().empty())
return nullptr;
125 for (HyperGraph::VertexIDMap::iterator it =
vertices().begin();
138 if (
vertices().empty())
return false;
142 for (HyperGraph::VertexIDMap::iterator it =
vertices().begin();
152 for (HyperGraph::EdgeSet::const_iterator eit = v->
edges().begin();
153 eit != v->
edges().end(); ++eit) {
171 for (
int k = 0; k < 2; k++)
172 for (VertexContainer::iterator it = vlist.begin(); it != vlist.end();
190 for (
size_t i = 0; i <
_ivMap.size(); ++i) {
191 _ivMap[i]->setHessianIndex(-1);
200 vset.insert(it->second);
206 if (
edges().size() == 0) {
207 G2O_WARN(
"Attempt to initialize an empty graph");
212 (void)workspaceAllocated;
213 assert(workspaceAllocated &&
214 "Error while allocating memory for the Jacobians");
219 set<Edge*> auxEdgeSet;
220 for (HyperGraph::VertexSet::iterator it = vset.begin(); it != vset.end();
226 for (OptimizableGraph::EdgeSet::const_iterator it = vEdges.begin();
227 it != vEdges.end(); ++it) {
230 if (level < 0 || e->level() == level) {
231 bool allVerticesOK =
true;
232 for (vector<HyperGraph::Vertex*>::const_iterator vit =
234 vit != e->
vertices().end(); ++vit) {
235 if (vset.find(*vit) == vset.end()) {
236 allVerticesOK =
false;
241 auxEdgeSet.insert(e);
252 if (estimateDim > 0) {
253 VectorX estimateData(estimateDim);
256 bool hasNan =
arrayHasNaN(estimateData.data(), estimateDim, &k);
258 G2O_WARN(
"{}: Vertex {} contains a nan entry at index {}",
267 for (set<Edge*>::iterator it = auxEdgeSet.begin(); it != auxEdgeSet.end();
274 return indexMappingStatus;
280 (void)workspaceAllocated;
281 assert(workspaceAllocated &&
282 "Error while allocating memory for the Jacobians");
287 set<Vertex*> auxVertexSet;
288 for (HyperGraph::EdgeSet::iterator it = eset.begin(); it != eset.end();
292 for (vector<HyperGraph::Vertex*>::const_iterator vit =
294 vit != e->
vertices().end(); ++vit) {
301 for (set<Vertex*>::iterator it = auxVertexSet.begin();
302 it != auxVertexSet.end(); ++it)
308 return indexMappingStatus;
328 std::set<Vertex*> backupVertices;
334 for (
size_t i = 0; i < e->
vertices().size(); ++i) {
339 fixedVertices.insert(v);
342 for (EdgeSet::const_iterator vedgeIt = v->
edges().begin();
343 vedgeIt != v->
edges().end(); ++vedgeIt) {
346 if (vedge->
vertices().size() == 1 &&
349 fixedVertices.insert(v);
354 std::set<Vertex*>::const_iterator foundIt = backupVertices.find(v);
355 if (foundIt == backupVertices.end()) {
357 backupVertices.insert(v);
364 estimatePropagator.
propagate(fixedVertices, costFunction);
367 for (std::set<Vertex*>::iterator it = backupVertices.begin();
368 it != backupVertices.end(); ++it) {
374 cerr <<
"iteration= -1\t chi2= " <<
activeChi2() <<
"\t time= 0.0"
376 <<
"\t (using initial guess from " << costFunction.
name() <<
")"
384 "{}: 0 vertices to optimize, maybe forgot to call "
385 "initializeOptimization()",
390 int cjIterations = 0;
403 OptimizationAlgorithm::SolverResult result = OptimizationAlgorithm::OK;
404 for (
int i = 0; i < iterations && !
terminate() && ok; i++) {
417 ok = (result == OptimizationAlgorithm::OK);
419 bool errorComputed =
false;
422 errorComputed =
true;
432 <<
"\t time= " << dts <<
"\t cumTime= " << cumTime
440 if (result == OptimizationAlgorithm::Fail) {
448 for (
size_t i = 0; i <
_ivMap.size(); ++i) {
471 std::vector<HyperGraph::Vertex*> newVertices;
472 newVertices.reserve(vset.size());
475 for (HyperGraph::EdgeSet::iterator it = eset.begin(); it != eset.end();
482 size_t next =
_ivMap.size();
483 for (HyperGraph::VertexSet::iterator it = vset.begin(); it != vset.end();
490 newVertices.push_back(v);
500 if (newVertices.size() != vset.size()) {
501 G2O_ERROR(
"{}: something went wrong, size mismatch {} != {}", vset.size(),
520SparseOptimizer::VertexContainer::const_iterator
522 VertexContainer::const_iterator lower = lower_bound(
525 if ((*lower) == v)
return lower;
531 EdgeContainer::const_iterator lower =
534 if ((*lower) == e)
return lower;
539 for (VertexContainer::iterator it = vlist.begin(); it != vlist.end(); ++it)
544 for (VertexContainer::iterator it = vlist.begin(); it != vlist.end(); ++it)
557 for (VertexContainer::iterator it = vlist.begin(); it != vlist.end(); ++it)
578 const std::vector<std::pair<int, int> >& blockIndices) {
584 if (
vertex->hessianIndex() < 0) {
587 std::vector<std::pair<int, int> > index{
588 std::make_pair<int, int>(
vertex->hessianIndex(),
vertex->hessianIndex())};
594 std::vector<std::pair<int, int> > indices;
596 for (VertexContainer::const_iterator it =
vertices.begin();
598 indices.emplace_back((*it)->hessianIndex(), (*it)->hessianIndex());
615 std::pair<HyperGraphActionSet::iterator, bool> insertResult =
617 return insertResult.second;
cost for traversing along active edges in the optimizer
virtual std::string_view name() const
propagation of an initial guess
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())
Abstract action that operates on an entire graph.
int numUndefinedVertices() const
const VertexContainer & vertices() const
const Vertex * vertex(size_t i) const
virtual void resize(size_t size)
abstract Vertex, your types must derive from that one
int id() const
returns the id
const EdgeSet & edges() const
returns the set of hyper-edges that are leaving/entering in this vertex
virtual bool removeVertex(Vertex *v, bool detach=false)
std::set< Edge * > EdgeSet
virtual void clear()
clears the graph and empties all structures.
std::set< Vertex * > VertexSet
std::vector< Vertex * > VertexContainer
const EdgeSet & edges() const
const VertexIDMap & vertices() const
int dimension() const
returns the dimensions of the error function
virtual double chi2() const =0
virtual double initialEstimatePossible(const OptimizableGraph::VertexSet &from, OptimizableGraph::Vertex *to)
virtual void computeError()=0
virtual bool allVerticesFixed() const =0
RobustKernel * robustKernel() const
if NOT NULL, error of this edge will be robustifed with the kernel
virtual const double * errorData() const =0
returns the error vector cached after calling the computeError;
virtual void initialEstimate(const OptimizableGraph::VertexSet &from, OptimizableGraph::Vertex *to)=0
A general case Vertex for optimization.
bool marginalized() const
true => this node is marginalized out during the optimization
void setHessianIndex(int ti)
set the temporary index of the vertex in the parameter blocks
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
void setToOrigin()
sets the node to the origin (used in the multilevel stuff)
virtual int estimateDimension() const
void oplus(const double *v)
Generic interface for a non-linear solver operating on a graph.
virtual bool computeMarginals(SparseBlockMatrix< MatrixX > &spinv, const std::vector< std::pair< int, int > > &blockIndices)=0
virtual void printVerbose(std::ostream &os) const
virtual bool updateStructure(const std::vector< HyperGraph::Vertex * > &vset, const HyperGraph::EdgeSet &edges)=0
virtual SolverResult solve(int iteration, bool online=false)=0
virtual bool init(bool online=false)=0
void setOptimizer(SparseOptimizer *optimizer)
virtual void robustify(double squaredError, Vector3 &rho) const =0
Sparse matrix which uses blocks.
void computeActiveErrors()
int optimize(int iterations, bool online=false)
const OptimizationAlgorithm * algorithm() const
the solver used by the optimizer
void discardTop()
same as above, but for the active vertices
BatchStatisticsContainer _batchStatistics
virtual bool removeVertex(HyperGraph::Vertex *v, bool detach=false)
EdgeContainer _activeEdges
sorted according to EdgeIDCompare
void setForceStopFlag(bool *flag)
EdgeContainer::const_iterator findActiveEdge(const OptimizableGraph::Edge *e) const
bool _computeBatchStatistics
virtual ~SparseOptimizer()
void setVerbose(bool verbose)
bool addComputeErrorAction(HyperGraphAction *action)
add an action to be executed before the error vectors are computed
void push()
push all the active vertices onto a stack
virtual bool initializeOptimization(HyperGraph::EdgeSet &eset)
virtual void computeInitialGuess()
void setAlgorithm(OptimizationAlgorithm *algorithm)
OptimizationAlgorithm * _algorithm
void setComputeBatchStatistics(bool computeBatchStatistics)
VertexContainer::const_iterator findActiveVertex(const OptimizableGraph::Vertex *v) const
VertexContainer _activeVertices
sorted according to VertexIDCompare
void sortVectorContainers()
void update(const double *update)
bool buildIndexMapping(SparseOptimizer::VertexContainer &vlist)
bool verbose() const
verbose information during optimization
double activeRobustChi2() const
virtual Vertex * findGauge()
finds a gauge in the graph to remove the undefined dof.
bool removeComputeErrorAction(HyperGraphAction *action)
double activeChi2() const
virtual void setToOrigin()
void pop()
pop (restore) the estimate of the active vertices from the stack
bool computeBatchStatistics() const
bool terminate()
if external stop flag is given, return its state. False otherwise
virtual bool updateInitialization(HyperGraph::VertexSet &vset, HyperGraph::EdgeSet &eset)
bool computeMarginals(SparseBlockMatrix< MatrixX > &spinv, const std::vector< std::pair< int, int > > &blockIndices)
#define __PRETTY_FUNCTION__
some general case utility functions
bool arrayHasNaN(const double *array, int size, int *nanIndex=0)
double get_monotonic_time()
VectorN< Eigen::Dynamic > VectorX
statistics about the optimization
int numVertices
how many vertices are involved
int iteration
which iteration
static void setGlobalStats(G2OBatchStatistics *b)
int numEdges
how many edges
order edges based on the internal ID, which is assigned to the edge in addEdge()
order vertices based on their ID
JacobianWorkspace _jacobianWorkspace
virtual void push()
push the estimate of all variables onto a stack
std::vector< OptimizableGraph::Vertex * > VertexContainer
vector container for vertices
std::vector< HyperGraphActionSet > _graphActions
virtual void pop()
pop (restore) the estimate of all variables from the stack
std::set< HyperGraphAction * > HyperGraphActionSet
virtual void postIteration(int)
virtual void preIteration(int)
int maxDimension() const
return the maximum dimension of all vertices in the graph
Vertex * vertex(int id)
returns the vertex number id appropriately casted
utility functions for handling time related stuff