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 #ifndef G2O_AIS_OPTIMIZABLE_GRAPH_HH_
28 #define G2O_AIS_OPTIMIZABLE_GRAPH_HH_
29 
30 #include <functional>
31 #include <iostream>
32 #include <set>
33 #include <typeinfo>
34 
35 #include "g2o/stuff/macros.h"
36 #include "g2o_core_api.h"
37 #include "hyper_graph.h"
38 #include "io_helper.h"
39 #include "jacobian_workspace.h"
40 #include "openmp_mutex.h"
41 #include "parameter.h"
42 #include "parameter_container.h"
43 
44 namespace g2o {
45 
46   class HyperGraphAction;
47   struct OptimizationAlgorithmProperty;
48   class CacheContainer;
49   class RobustKernel;
50 
51   /**
52      @addtogroup g2o
53    */
54   /**
55      This is an abstract class that represents one optimization
56      problem.  It specializes the general graph to contain special
57      vertices and edges.  The vertices represent parameters that can
58      be optimized, while the edges represent constraints.  This class
59      also provides basic functionalities to handle the backup/restore
60      of portions of the vertices.
61    */
62   struct G2O_CORE_API OptimizableGraph : public HyperGraph {
63 
64     enum ActionType {
65       AT_PREITERATION, AT_POSTITERATION,
66       AT_NUM_ELEMENTS, // keep as last element
67     };
68 
69     typedef std::set<HyperGraphAction*>    HyperGraphActionSet;
70 
71     // forward declarations
72     class G2O_CORE_API Vertex;
73     class G2O_CORE_API Edge;
74 
75 
76     /**
77      * \brief order vertices based on their ID
78      */
79     struct G2O_CORE_API VertexIDCompare {
operatorOptimizableGraph::VertexIDCompare80       bool operator() (const Vertex* v1, const Vertex* v2) const
81       {
82         return v1->id() < v2->id();
83       }
84     };
85 
86     /**
87      * \brief order edges based on the internal ID, which is assigned to the edge in addEdge()
88      */
89     struct G2O_CORE_API EdgeIDCompare {
operatorOptimizableGraph::EdgeIDCompare90       bool operator() (const Edge* e1, const Edge* e2) const
91       {
92         return e1->internalId() < e2->internalId();
93       }
operatorOptimizableGraph::EdgeIDCompare94       bool operator() (const HyperGraph::Edge* e1, const HyperGraph::Edge* e2) const
95       {
96         return operator()(static_cast<const Edge*>(e1), static_cast<const Edge*>(e2));
97       }
98     };
99 
100     //! vector container for vertices
101     typedef std::vector<OptimizableGraph::Vertex*>      VertexContainer;
102     //! vector container for edges
103     typedef std::vector<OptimizableGraph::Edge*>        EdgeContainer;
104 
105     /**
106      * \brief A general case Vertex for optimization
107      */
108     class G2O_CORE_API Vertex : public HyperGraph::Vertex, public HyperGraph::DataContainer {
109       private:
110         friend struct OptimizableGraph;
111       public:
112         Vertex();
113         virtual ~Vertex();
114 
115         //! sets the node to the origin (used in the multilevel stuff)
setToOriginOptimizableGraph116         void setToOrigin() { setToOriginImpl(); updateCache();}
117 
118         //! get the element from the hessian matrix
119         virtual const number_t& hessian(int i, int j) const = 0;
120         virtual number_t& hessian(int i, int j) = 0;
121         virtual number_t hessianDeterminant() const = 0;
122         virtual number_t* hessianData() = 0;
123 
124         /** maps the internal matrix to some external memory location */
125         virtual void mapHessianMemory(number_t* d) = 0;
126 
127         /**
128          * copies the b vector in the array b_
129          * @return the number of elements copied
130          */
131         virtual int copyB(number_t* b_) const = 0;
132 
133         //! get the b vector element
134         virtual const number_t& b(int i) const = 0;
135         virtual number_t& b(int i) = 0;
136         //! return a pointer to the b vector associated with this vertex
137         virtual number_t* bData() = 0;
138 
139         /**
140          * set the b vector part of this vertex to zero
141          */
142         virtual void clearQuadraticForm() = 0;
143 
144         /**
145          * updates the current vertex with the direct solution x += H_ii\b_ii
146          * @return the determinant of the inverted hessian
147          */
148         virtual number_t solveDirect(number_t lambda=0) = 0;
149 
150         /**
151          * sets the initial estimate from an array of number_t
152          * Implement setEstimateDataImpl()
153          * @return true on success
154          */
155         bool setEstimateData(const number_t* estimate);
156 
157         /**
158          * sets the initial estimate from an array of number_t
159          * Implement setEstimateDataImpl()
160          * @return true on success
161          */
setEstimateDataOptimizableGraph162         bool setEstimateData(const std::vector<number_t>& estimate) {
163 #ifndef NDEBUG
164           int dim = estimateDimension();
165           assert((dim == -1) || (estimate.size() == std::size_t(dim)));
166 #endif
167           return setEstimateData(&estimate[0]);
168         };
169 
170         /**
171          * writes the estimater to an array of number_t
172          * @returns true on success
173          */
174         virtual bool getEstimateData(number_t* estimate) const;
175 
176         /**
177          * writes the estimater to an array of number_t
178          * @returns true on success
179          */
getEstimateDataOptimizableGraph180         virtual bool getEstimateData(std::vector<number_t>& estimate) const {
181           int dim = estimateDimension();
182           if (dim < 0)
183             return false;
184           estimate.resize(dim);
185           return getEstimateData(&estimate[0]);
186         };
187 
188         /**
189          * returns the dimension of the extended representation used by get/setEstimate(number_t*)
190          * -1 if it is not supported
191          */
192         virtual int estimateDimension() const;
193 
194         /**
195          * sets the initial estimate from an array of number_t.
196          * Implement setMinimalEstimateDataImpl()
197          * @return true on success
198          */
199         bool setMinimalEstimateData(const number_t* estimate);
200 
201         /**
202          * sets the initial estimate from an array of number_t.
203          * Implement setMinimalEstimateDataImpl()
204          * @return true on success
205          */
setMinimalEstimateDataOptimizableGraph206         bool setMinimalEstimateData(const std::vector<number_t>& estimate) {
207 #ifndef NDEBUG
208           int dim = minimalEstimateDimension();
209           assert((dim == -1) || (estimate.size() == std::size_t(dim)));
210 #endif
211           return setMinimalEstimateData(&estimate[0]);
212         };
213 
214         /**
215          * writes the estimate to an array of number_t
216          * @returns true on success
217          */
218         virtual bool getMinimalEstimateData(number_t* estimate) const ;
219 
220         /**
221          * writes the estimate to an array of number_t
222          * @returns true on success
223          */
getMinimalEstimateDataOptimizableGraph224         virtual bool getMinimalEstimateData(std::vector<number_t>& estimate) const {
225           int dim = minimalEstimateDimension();
226           if (dim < 0)
227             return false;
228           estimate.resize(dim);
229           return getMinimalEstimateData(&estimate[0]);
230         };
231 
232         /**
233          * returns the dimension of the extended representation used by get/setEstimate(number_t*)
234          * -1 if it is not supported
235          */
236         virtual int minimalEstimateDimension() const;
237 
238         //! backup the position of the vertex to a stack
239         virtual void push() = 0;
240 
241         //! restore the position of the vertex by retrieving the position from the stack
242         virtual void pop() = 0;
243 
244         //! pop the last element from the stack, without restoring the current estimate
245         virtual void discardTop() = 0;
246 
247         //! return the stack size
248         virtual int stackSize() const = 0;
249 
250         /**
251          * Update the position of the node from the parameters in v.
252          * Depends on the implementation of oplusImpl in derived classes to actually carry
253          * out the update.
254          * Will also call updateCache() to update the caches of depending on the vertex.
255          */
oplusOptimizableGraph256         void oplus(const number_t* v)
257         {
258           oplusImpl(v);
259           updateCache();
260         }
261 
262         //! temporary index of this node in the parameter vector obtained from linearization
hessianIndexOptimizableGraph263         int hessianIndex() const { return _hessianIndex;}
G2O_ATTRIBUTE_DEPRECATEDOptimizableGraph264         int G2O_ATTRIBUTE_DEPRECATED(tempIndex() const) { return hessianIndex();}
265         //! set the temporary index of the vertex in the parameter blocks
setHessianIndexOptimizableGraph266         void setHessianIndex(int ti) { _hessianIndex = ti;}
G2O_ATTRIBUTE_DEPRECATEDOptimizableGraph267         void G2O_ATTRIBUTE_DEPRECATED(setTempIndex(int ti)) { setHessianIndex(ti);}
268 
269         //! true => this node is fixed during the optimization
fixedOptimizableGraph270         bool fixed() const {return _fixed;}
271         //! true => this node should be considered fixed during the optimization
setFixedOptimizableGraph272         void setFixed(bool fixed) { _fixed = fixed;}
273 
274         //! true => this node is marginalized out during the optimization
marginalizedOptimizableGraph275         bool marginalized() const {return _marginalized;}
276         //! true => this node should be marginalized out during the optimization
setMarginalizedOptimizableGraph277         void setMarginalized(bool marginalized) { _marginalized = marginalized;}
278 
279         //! dimension of the estimated state belonging to this node
dimensionOptimizableGraph280         int dimension() const { return _dimension;}
281 
282         //! sets the id of the node in the graph be sure that the graph keeps consistent after changing the id
setIdOptimizableGraph283         virtual void setId(int id) {_id = id;}
284 
285         //! set the row of this vertex in the Hessian
setColInHessianOptimizableGraph286         void setColInHessian(int c) { _colInHessian = c;}
287         //! get the row of this vertex in the Hessian
colInHessianOptimizableGraph288         int colInHessian() const {return _colInHessian;}
289 
graphOptimizableGraph290         const OptimizableGraph* graph() const {return _graph;}
graphOptimizableGraph291         OptimizableGraph* graph() {return _graph;}
292 
293         /**
294          * lock for the block of the hessian and the b vector associated with this vertex, to avoid
295          * race-conditions if multi-threaded.
296          */
lockQuadraticFormOptimizableGraph297         void lockQuadraticForm() { _quadraticFormMutex.lock();}
298         /**
299          * unlock the block of the hessian and the b vector associated with this vertex
300          */
unlockQuadraticFormOptimizableGraph301         void unlockQuadraticForm() { _quadraticFormMutex.unlock();}
302 
303         //! read the vertex from a stream, i.e., the internal state of the vertex
304         virtual bool read(std::istream& is) = 0;
305         //! write the vertex to a stream
306         virtual bool write(std::ostream& os) const = 0;
307 
308         virtual void updateCache();
309 
310         CacheContainer* cacheContainer();
311       protected:
312         OptimizableGraph* _graph;
313         Data* _userData;
314         int _hessianIndex;
315         bool _fixed;
316         bool _marginalized;
317         int _dimension;
318         int _colInHessian;
319         OpenMPMutex _quadraticFormMutex;
320 
321         CacheContainer* _cacheContainer;
322 
323         /**
324          * update the position of the node from the parameters in v.
325          * Implement in your class!
326          */
327         virtual void oplusImpl(const number_t* v) = 0;
328 
329         //! sets the node to the origin (used in the multilevel stuff)
330         virtual void setToOriginImpl() = 0;
331 
332         /**
333          * writes the estimater to an array of number_t
334          * @returns true on success
335          */
setEstimateDataImplOptimizableGraph336         virtual bool setEstimateDataImpl(const number_t* ) { return false;}
337 
338         /**
339          * sets the initial estimate from an array of number_t
340          * @return true on success
341          */
setMinimalEstimateDataImplOptimizableGraph342         virtual bool setMinimalEstimateDataImpl(const number_t* ) { return false;}
343 
344     };
345 
346     class G2O_CORE_API Edge: public HyperGraph::Edge, public HyperGraph::DataContainer {
347       private:
348         friend struct OptimizableGraph;
349 
350     public:
351         Edge();
352         virtual ~Edge();
353 
354         // indicates if all vertices are fixed
355         virtual bool allVerticesFixed() const = 0;
356 
357         // computes the error of the edge and stores it in an internal structure
358         virtual void computeError() = 0;
359 
360         //! sets the measurement from an array of number_t
361         //! @returns true on success
362         virtual bool setMeasurementData(const number_t* m);
363 
364         //! writes the measurement to an array of number_t
365         //! @returns true on success
366         virtual bool getMeasurementData(number_t* m) const;
367 
368         //! returns the dimension of the measurement in the extended representation which is used
369         //! by get/setMeasurement;
370         virtual int measurementDimension() const;
371 
372         /**
373          * sets the estimate to have a zero error, based on the current value of the state variables
374          * returns false if not supported.
375          */
376         virtual bool setMeasurementFromState();
377 
378         //! if NOT NULL, error of this edge will be robustifed with the kernel
robustKernelOptimizableGraph379         RobustKernel* robustKernel() const { return _robustKernel;}
380         /**
381          * specify the robust kernel to be used in this edge
382          */
383         void setRobustKernel(RobustKernel* ptr);
384 
385         //! returns the error vector cached after calling the computeError;
386         virtual const number_t* errorData() const = 0;
387         virtual number_t* errorData() = 0;
388 
389         //! returns the memory of the information matrix, usable for example with a Eigen::Map<MatrixX>
390         virtual const number_t* informationData() const = 0;
391         virtual number_t* informationData() = 0;
392 
393         //! computes the chi2 based on the cached error value, only valid after computeError has been called.
394         virtual number_t chi2() const = 0;
395 
396         /**
397          * Linearizes the constraint in the edge.
398          * Makes side effect on the vertices of the graph by changing
399          * the parameter vector b and the hessian blocks ii and jj.
400          * The off diagoinal block is accesed via _hessian.
401          */
402         virtual void constructQuadraticForm() = 0;
403 
404         /**
405          * maps the internal matrix to some external memory location,
406          * you need to provide the memory before calling constructQuadraticForm
407          * @param d the memory location to which we map
408          * @param i index of the vertex i
409          * @param j index of the vertex j (j > i, upper triangular fashion)
410          * @param rowMajor if true, will write in rowMajor order to the block. Since EIGEN is columnMajor by default, this results in writing the transposed
411          */
412         virtual void mapHessianMemory(number_t* d, int i, int j, bool rowMajor) = 0;
413 
414         /**
415          * Linearizes the constraint in the edge in the manifold space, and store
416          * the result in the given workspace
417          */
418         virtual void linearizeOplus(JacobianWorkspace& jacobianWorkspace) = 0;
419 
420         /** set the estimate of the to vertex, based on the estimate of the from vertices in the edge. */
421         virtual void initialEstimate(const OptimizableGraph::VertexSet& from, OptimizableGraph::Vertex* to) = 0;
422 
423         /**
424          * override in your class if it's possible to initialize the vertices in certain combinations.
425          * The return value may correspond to the cost for initiliaizng the vertex but should be positive if
426          * the initialization is possible and negative if not possible.
427          */
initialEstimatePossibleOptimizableGraph428         virtual number_t initialEstimatePossible(const OptimizableGraph::VertexSet& from, OptimizableGraph::Vertex* to) { (void) from; (void) to; return -1.;}
429 
430         //! returns the level of the edge
levelOptimizableGraph431         int level() const { return _level;}
432         //! sets the level of the edge
setLevelOptimizableGraph433         void setLevel(int l) { _level=l;}
434 
435         //! returns the dimensions of the error function
dimensionOptimizableGraph436         int dimension() const { return _dimension;}
437 
G2O_ATTRIBUTE_DEPRECATEDOptimizableGraph438         G2O_ATTRIBUTE_DEPRECATED(virtual Vertex* createFrom()) { return nullptr; }
G2O_ATTRIBUTE_DEPRECATEDOptimizableGraph439         G2O_ATTRIBUTE_DEPRECATED(virtual Vertex* createTo()) { return nullptr; }
createVertexOptimizableGraph440         virtual Vertex* createVertex(int) { return nullptr; }
441 
442         //! read the vertex from a stream, i.e., the internal state of the vertex
443         virtual bool read(std::istream& is) = 0;
444         //! write the vertex to a stream
445         virtual bool write(std::ostream& os) const = 0;
446 
447         //! the internal ID of the edge
internalIdOptimizableGraph448         long long internalId() const { return _internalId;}
449 
450         OptimizableGraph* graph();
451         const OptimizableGraph* graph() const;
452 
453         bool setParameterId(int argNum, int paramId);
parameterOptimizableGraph454         inline const Parameter* parameter(int argNo) const {return *_parameters.at(argNo);}
numParametersOptimizableGraph455         inline size_t numParameters() const {return _parameters.size();}
resizeParametersOptimizableGraph456         inline void resizeParameters(size_t newSize) {
457           _parameters.resize(newSize, 0);
458           _parameterIds.resize(newSize, -1);
459           _parameterTypes.resize(newSize, typeid(void*).name());
460         }
461       protected:
462        int _dimension;
463        int _level;
464        RobustKernel* _robustKernel;
465        long long _internalId;
466        std::vector<int> _cacheIds;
467 
468        template <typename ParameterType>
469        bool installParameter(ParameterType*& p, size_t argNo, int paramId = -1) {
470          if (argNo >= _parameters.size()) return false;
471          _parameterIds[argNo] = paramId;
472          _parameters[argNo] = (Parameter**)&p;
473          _parameterTypes[argNo] = typeid(ParameterType).name();
474          return true;
475        }
476 
477        template <typename CacheType>
478        void resolveCache(CacheType*& cache, OptimizableGraph::Vertex*, const std::string& _type,
479                          const ParameterVector& parameters);
480 
481        bool resolveParameters();
482        virtual bool resolveCaches();
483 
484        std::vector<std::string> _parameterTypes;
485        std::vector<Parameter**> _parameters;
486        std::vector<int> _parameterIds;
487     };
488 
489     //! returns the vertex number <i>id</i> appropriately casted
vertexOptimizableGraph490     inline Vertex* vertex(int id) { return reinterpret_cast<Vertex*>(HyperGraph::vertex(id));}
491 
492     //! returns the vertex number <i>id</i> appropriately casted
vertexOptimizableGraph493     inline const Vertex* vertex (int id) const{ return reinterpret_cast<const Vertex*>(HyperGraph::vertex(id));}
494 
495     //! empty constructor
496     OptimizableGraph();
497     virtual ~OptimizableGraph();
498 
499     /**
500      * adds a new vertex. The new vertex is then "taken".
501      * @return false if a vertex with the same id as v is already in the graph, true otherwise.
502      */
503     virtual bool addVertex(HyperGraph::Vertex* v, Data* userData);
addVertexOptimizableGraph504     virtual bool addVertex(HyperGraph::Vertex* v) { return addVertex(v, 0);}
505     bool addVertex(OptimizableGraph::Vertex* v, Data* userData);
addVertexOptimizableGraph506     bool addVertex(OptimizableGraph::Vertex* v) { return addVertex(v, 0); }
507 
508     /**
509      * adds a new edge.
510      * The edge should point to the vertices that it is connecting (setFrom/setTo).
511      * @return false if the insertion does not work (incompatible types of the vertices/missing vertex). true otherwise.
512      */
513     virtual bool addEdge(HyperGraph::Edge* e);
514     bool addEdge(OptimizableGraph::Edge* e);
515 
516     /**
517      * overridden from HyperGraph, to mantain the bookkeeping of the caches/parameters and jacobian workspaces consistent upon a change in the veretx.
518      * @return false if something goes wriong.
519      */
520     virtual bool setEdgeVertex(HyperGraph::Edge* e, int pos, HyperGraph::Vertex* v);
521 
522     //! returns the chi2 of the current configuration
523     number_t chi2() const;
524 
525     //! return the maximum dimension of all vertices in the graph
526     int maxDimension() const;
527 
528     //! Recompute the size of the Jacobian workspace from all the
529     //! edges in the graph.
recomputeJacobianWorkspaceSizeOptimizableGraph530     void recomputeJacobianWorkspaceSize()
531     {
532       _jacobianWorkspace.updateSize(*this, true);
533     }
534 
535     /**
536      * iterates over all vertices and returns a set of all the vertex dimensions in the graph
537      */
538     std::set<int> dimensions() const;
539 
540     /**
541      * carry out n iterations
542      * @return the number of performed iterations
543      */
544     virtual int optimize(int iterations, bool online=false);
545 
546     //! called at the beginning of an iteration (argument is the number of the iteration)
547     virtual void preIteration(int);
548     //! called at the end of an iteration (argument is the number of the iteration)
549     virtual void postIteration(int);
550 
551     //! add an action to be executed before each iteration
552     bool addPreIterationAction(HyperGraphAction* action);
553     //! add an action to be executed after each iteration
554     bool addPostIterationAction(HyperGraphAction* action);
555 
556     //! remove an action that should no longer be execured before each iteration
557     bool removePreIterationAction(HyperGraphAction* action);
558     //! remove an action that should no longer be execured after each iteration
559     bool removePostIterationAction(HyperGraphAction* action);
560 
561     //! push the estimate of all variables onto a stack
562     virtual void push();
563     //! pop (restore) the estimate of all variables from the stack
564     virtual void pop();
565     //! discard the last backup of the estimate for all variables by removing it from the stack
566     virtual void discardTop();
567 
568 
569 
570     //! load the graph from a stream. Uses the Factory singleton for creating the vertices and edges.
571     virtual bool load(std::istream& is);
572     bool load(const char* filename);
573     //! save the graph to a stream. Again uses the Factory system.
574     virtual bool save(std::ostream& os, int level = 0) const;
575     //! function provided for convenience, see save() above
576     bool save(const char* filename, int level = 0) const;
577 
578 
579     //! save a subgraph to a stream. Again uses the Factory system.
580     bool saveSubset(std::ostream& os, HyperGraph::VertexSet& vset, int level = 0);
581 
582     //! save a subgraph to a stream. Again uses the Factory system.
583     bool saveSubset(std::ostream& os, HyperGraph::EdgeSet& eset);
584 
585     //! push the estimate of a subset of the variables onto a stack
586     virtual void push(HyperGraph::VertexSet& vset);
587     //! pop (restore) the estimate a subset of the variables from the stack
588     virtual void pop(HyperGraph::VertexSet& vset);
589     //! ignore the latest stored element on the stack, remove it from the stack but do not restore the estimate
590     virtual void discardTop(HyperGraph::VertexSet& vset);
591 
592     //! fixes/releases a set of vertices
593     virtual void setFixed(HyperGraph::VertexSet& vset, bool fixed);
594 
595     /**
596      * set the renamed types lookup from a string, format is for example:
597      * VERTEX_CAM=VERTEX_SE3:EXPMAP,EDGE_PROJECT_P2MC=EDGE_PROJECT_XYZ:EXPMAP
598      * This will change the occurance of VERTEX_CAM in the file to VERTEX_SE3:EXPMAP
599      */
600     void setRenamedTypesFromString(const std::string& types);
601 
602     /**
603      * test whether a solver is suitable for optimizing this graph.
604      * @param solverProperty the solver property to evaluate.
605      * @param vertDims should equal to the set returned by dimensions() to avoid re-evaluating.
606      */
607     bool isSolverSuitable(const OptimizationAlgorithmProperty& solverProperty, const std::set<int>& vertDims = std::set<int>()) const;
608 
609     /**
610      * remove the parameters of the graph
611      */
612     virtual void clearParameters();
613 
addParameterOptimizableGraph614     bool addParameter(Parameter* p) {
615       return _parameters.addParameter(p);
616     }
617 
parameterOptimizableGraph618     Parameter* parameter(int id) {
619       return _parameters.getParameter(id);
620     }
621 
622     /**
623      * verify that all the information of the edges are semi positive definite, i.e.,
624      * all Eigenvalues are >= 0.
625      * @param verbose output edges with not PSD information matrix on cerr
626      * @return true if all edges have PSD information matrix
627      */
628     bool verifyInformationMatrices(bool verbose = false) const;
629 
630     // helper functions to save an individual vertex
631     bool saveVertex(std::ostream& os, Vertex* v) const;
632 
633     // helper function to save an individual parameter
634     bool saveParameter(std::ostream& os, Parameter* v) const;
635 
636     // helper functions to save an individual edge
637     bool saveEdge(std::ostream& os, Edge* e) const;
638 
639     // helper functions to save the data packets
640     bool saveUserData(std::ostream& os, HyperGraph::Data* v) const;
641 
642     //! the workspace for storing the Jacobians of the graph
jacobianWorkspaceOptimizableGraph643     JacobianWorkspace& jacobianWorkspace() { return _jacobianWorkspace;}
jacobianWorkspaceOptimizableGraph644     const JacobianWorkspace& jacobianWorkspace() const { return _jacobianWorkspace;}
645 
646     /**
647      * Eigen starting from version 3.1 requires that we call an initialize
648      * function, if we perform calls to Eigen from several threads.
649      * Currently, this function calls Eigen::initParallel if g2o is compiled
650      * with OpenMP support and Eigen's version is at least 3.1
651      */
652     static bool initMultiThreading();
653 
parametersOptimizableGraph654     inline ParameterContainer& parameters() {return _parameters;}
parametersOptimizableGraph655     inline const ParameterContainer& parameters() const {return _parameters;}
656 
657     //! apply a unary function to all vertices
658     void forEachVertex(std::function<void(OptimizableGraph::Vertex*)> fn);
659     //! apply a unary function to the vertices in vset
660     void forEachVertex(HyperGraph::VertexSet& vset, std::function<void(OptimizableGraph::Vertex*)> fn);
661 
662   protected:
663     std::map<std::string, std::string> _renamedTypesLookup;
664     long long _nextEdgeId;
665     std::vector<HyperGraphActionSet> _graphActions;
666 
667     ParameterContainer _parameters;
668     JacobianWorkspace _jacobianWorkspace;
669 
670     void performActions(int iter, HyperGraphActionSet& actions);
671   };
672 
673   /**
674     @}
675    */
676 
677 } // end namespace
678 
679 #endif
680