NDEVR
API Documentation
sparse_optimizer.h
1#pragma once
2#include "macros.h"
3
4#include "optimizable_graph.h"
5
6namespace NDEVR {
7
8 // forward declaration
9 class ActivePathCostFunction;
11
13 class SparseOptimizer : public OptimizableGraph
14 {
15 public:
17 enum
18 {
19 AT_COMPUTEACTIVERROR = OptimizableGraph::AT_NUM_ELEMENTS,
20 AT_NUM_ELEMENTS, // keep as last element
21 };
22
23 friend class ActivePathCostFunction;
24
26 bool isReadyToUpdate() const
27 {
28 return _ivMap.size() != 0;
29 }
30
31
32
34 bool* forceStopFlag() const { return _forceStopFlag; };
35
37 bool terminate() { return _forceStopFlag ? (*_forceStopFlag) : false; }
38
40 const VertexContainer& indexMapping() const { return _ivMap; }
44 const EdgeContainer& activeEdges() const { return _activeEdges; }
45
46
51 G2O_ATTRIBUTE_DEPRECATED(void linearizeSystem())
52 {
53 // nothing needed, linearization is now done inside the solver
54 }
55
61 void update(const g_type* update)
62 {
63 // update the graph by calling oplus on the vertices
64 for (uint04 i = 0; i < _ivMap.size(); ++i)
65 {
66 OGVertex* v = _ivMap[i];
67 v->oplus(update);
68 update += v->dimension();
69 }
70 }
73 {
74 //_graphActions.resize(AT_NUM_ELEMENTS);
75 }
76
81 {
82 // call the callbacks in case there is something registered
84 e->computeError();
85 }
86
88 g_type activeChi2() const
89 {
90 g_type chi = 0.0;
91 for (auto it = _activeEdges.begin(); it != _activeEdges.end(); ++it) {
92 const OptimizableGraph::OGEdge* e = *it;
93 chi += e->chi2();
94 }
95 return chi;
96 }
97
99 g_type activeRobustChi2() const
100 {
101 Eigen::Vector3<g_type> rho;
102 g_type chi = 0.0;
103 for (auto& e : _activeEdges)
104 {
105 if (e->robustKernel())
106 {
107 e->robustKernel()->robustify(e->chi2(), rho);
108 chi += rho[0];
109 }
110 else
111 {
112 chi += e->chi2();
113 }
114 }
115 return chi;
116 }
117
120 if (vertices().empty())
121 return 0;
122
123 sint04 maxDim = 0;
124 for (auto it = vertices().begin(); it != vertices().end(); ++it) {
125 OGVertex* v = static_cast<OGVertex*>(it->second);
126 maxDim = getMax(maxDim, v->dimension());
127 }
128
129 OGVertex* rut = 0;
130 for (auto it = vertices().begin(); it != vertices().end(); ++it)
131 {
132 OGVertex* v = static_cast<OGVertex*>(it->second);
133 if (v->dimension() == maxDim)
134 {
135 rut = v;
136 break;
137 }
138 }
139 return rut;
140 }
141
144 {
145 if (vertices().empty())
146 return false;
147
148 sint04 maxDim = 0;
149 for (auto it = vertices().begin(); it != vertices().end(); ++it) {
150 OGVertex* v = static_cast<OGVertex*>(it->second);
151 maxDim = getMax(maxDim, v->dimension());
152 }
153
154 for (auto it = vertices().begin(); it != vertices().end(); ++it) {
155 OGVertex* v = static_cast<OGVertex*>(it->second);
156 if (v->dimension() == maxDim) {
157 // test for fixed vertex
158 if (v->fixed()) {
159 return false;
160 }
161 // test for full dimension prior
162 for (auto eit = v->edges().begin(); eit != v->edges().end(); ++eit)
163 {
164 OptimizableGraph::OGEdge* e = static_cast<OptimizableGraph::OGEdge*>(*eit);
165 if (e->vertexCount() == 1 && e->dimension() == maxDim)
166 return false;
167 }
168 }
169 }
170 return true;
171 }
172
177 if (!vlist.size()) {
178 _ivMap.clear();
179 return false;
180 }
181
182 _ivMap.resize(vlist.size());
183 uint04 i = 0;
184 for (int k = 0; k < 2; k++)
185 for (auto it = vlist.begin(); it != vlist.end(); ++it) {
186 OGVertex* v = *it;
187 if (!v->fixed()) {
188 if (static_cast<int>(v->marginalized()) == k) {
189 v->setHessianIndex(i);
190 _ivMap[i] = v;
191 i++;
192 }
193 }
194 else {
195 v->setHessianIndex(-1);
196 }
197 }
198 _ivMap.resize(i);
199 return true;
200 }
201
204 for (uint04 i = 0; i < _ivMap.size(); ++i) {
205 _ivMap[i]->setHessianIndex(-1);
206 _ivMap[i] = 0;
207 }
208 }
209
217
221 bool initializeOptimization(int level = 0)
222 {
223 if (edges().size() == 0)
224 {
225 lib_assert(false, ": Attempt to initialize an empty graph");
226 return false;
227 }
228 auto& vset = vertices();
229 _jacobianWorkspace.allocate();
231 _activeVertices.clear();
232 _activeVertices.ensureCapacity(cast<uint04>(vset.size()));
233 _activeEdges.clear();
234 Set<OGEdge*> auxEdgeSet; // temporary structure to avoid duplicates
235 for (const auto& vset_it : vset)
236 {
237 OGVertex* v = (OGVertex*)vset_it.second;
238 const Buffer<HyperGraph::HGEdge*>& vEdges = v->edges();
239 // count if there are edges in that level. If not remove from the pool
240 int levelEdges = 0;
241 for (auto it = vEdges.begin(); it != vEdges.end(); ++it)
242 {
244 if (level < 0 || e->level() == level)
245 {
246 bool allVerticesOK = e->vertexCount() > 0;
247 for (uint04 i = 0; i < e->vertexCount(); i++)
248 {
249 if (!vset.hasKey(e->vertex(i)->id()))
250 {
251 allVerticesOK = false;
252 break;
253 }
254 }
255 if (allVerticesOK && !e->allVerticesFixed())
256 {
257 auxEdgeSet.insert(e);
258 levelEdges++;
259 }
260
261 }
262 }
263 if (levelEdges)
264 {
265 _activeVertices.add(v);
266 }
267 }
268
269 _activeEdges.ensureCapacity(auxEdgeSet.size());
270 for (auto it = auxEdgeSet.begin(); it != auxEdgeSet.end(); ++it)
271 _activeEdges.add(*it);
272
275 }
276
281 {
282 _jacobianWorkspace.allocate();
284 _activeVertices.clear();
285 _activeEdges.clear();
286 _activeEdges.ensureCapacity(cast<uint04>(eset.size()));
287 Set<OGVertex*> auxVertexSet; // temporary structure to avoid duplicates
288 for (auto it = eset.begin(); it != eset.end(); ++it)
289 {
291 for (uint04 i = 0; i < e->vertexCount(); i++)
292 auxVertexSet.insert(cast<OGVertex*>(e->vertex(i)));
293 _activeEdges.add(reinterpret_cast<OptimizableGraph::OGEdge*>(*it));
294 }
295
296 _activeVertices.ensureCapacity(cast<uint04>(auxVertexSet.size()));
297 for (auto it = auxVertexSet.begin(); it != auxVertexSet.end(); ++it)
298 _activeVertices.add(*it);
299
302 }
303
304 /*void setToOrigin()
305 {
306 for (VertexIDMap::iterator it = vertices().begin(); it != vertices().end(); ++it) {
307 OGVertex* v = static_cast<OGVertex*>(it->second);
308 v->setToOrigin();
309 }
310 }*/
312 void clear() final override
313 {
314 _ivMap.clear();
315 _activeVertices.clear();
316 _activeEdges.clear();
318 }
319
323 OGVertex* const* findActiveVertex(const OGVertex* v) const
324 {
325 auto lower = std::lower_bound(_activeVertices.begin(), _activeVertices.end(), v, VertexIDCompare());
326 if (lower == _activeVertices.end())
327 return _activeVertices.end();
328 if ((*lower) == v)
329 return lower;
330 return _activeVertices.end();
331 }
332
337 {
338 auto lower = std::lower_bound(_activeEdges.begin(), _activeEdges.end(), e, EdgeIDCompare());
339 if (lower == _activeEdges.end())
340 return _activeEdges.end();
341 if ((*lower) == e)
342 return lower;
343 return _activeEdges.end();
344 }
345
347 {
348 for (auto it = vlist.begin(); it != vlist.end(); ++it)
349 (*it)->push();
350 }
351
353 {
354 for (auto it = vlist.begin(); it != vlist.end(); ++it)
355 (*it)->pop();
356 }
357
358 void push(Set<HyperGraph::HGVertex*>& vlist) final override
359 {
360 for (auto it = vlist.begin(); it != vlist.end(); ++it)
361 {
362 OGVertex* v = dynamic_cast<OGVertex*>(*it);
363 if (v)
364 v->push();
365 }
366 }
367
368 void pop(Set<HyperGraph::HGVertex*>& vlist) final override
369 {
370 for (auto it = vlist.begin(); it != vlist.end(); ++it)
371 {
372 OGVertex* v = dynamic_cast<OGVertex*> (*it);
373 if (v)
374 v->pop();
375 //else
376 //std::cerr << __FUNCTION__ << ": FATAL POP SET" << std::endl;
377 }
378 }
379
381 {
382 for (auto it = vlist.begin(); it != vlist.end(); ++it)
383 (*it)->discardTop();
384 }
385
386
390 void setForceStopFlag(bool* flag)
391 {
392 _forceStopFlag = flag;
393 }
394
401 /*bool removeVertex(HyperGraph::HGVertex* v) final override
402 {
403 OGVertex* vv = static_cast<OGVertex*>(v);
404 if (vv->hessianIndex() >= 0) {
405 clearIndexMapping();
406 _ivMap.clear();
407 }
408 return HyperGraph::removeVertex(v);
409 }*/
410
411
412
413 void push() final override
414 {
416 }
417
418 void pop() final override
419 {
421 }
422
423 void discardTop() final override
424 {
426 }
427
428 protected:
430
434
437 {
438 // sort vector structures to get deterministic ordering based on IDs
439 std::sort(_activeVertices.begin(), _activeVertices.end(), VertexIDCompare());
440 std::sort(_activeEdges.begin(), _activeEdges.end(), EdgeIDCompare());
441 }
442
446 public:
447 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
448 };
449
450}
The equivelent of std::vector but with a bit more control.
Definition Buffer.hpp:58
virtual const HGVertex * vertex(uint04 i) const =0
Returns a const pointer to the i-th vertex.
virtual uint04 vertexCount() const =0
Returns the number of vertices connected by this edge.
int id() const
returns the id
Definition hyper_graph.h:37
const Buffer< HGEdge * > & edges() const
returns the set of hyper-edges that are leaving/entering in this vertex
Definition hyper_graph.h:41
virtual void clear()
removes a vertex from the graph. Returns true on success (vertex was present)
const Dictionary< int, HGVertex * > & vertices() const
const Buffer< HGEdge * > & edges() const
Base edge class for the optimizable graph, adding error computation and robust kernels.
virtual sint04 dimension() const =0
returns the dimensions of the error function
virtual g_type chi2() const =0
computes the chi2 based on the cached error value, only valid after computeError has been called.
virtual bool allVerticesFixed() const =0
Returns true if all vertices connected to this edge are fixed.
A general case Vertex for optimization.
bool fixed() const
true => this node is fixed during the optimization
virtual sint04 dimension() const =0
dimension of the estimated state belonging to this node
bool marginalized() const
true => this node is marginalized out during the optimization
virtual void push()=0
backup the position of the vertex to a stack
void oplus(const g_type *v)
Update the position of the node from the parameters in v.
virtual void pop()=0
restore the position of the vertex by retrieving the position from the stack
void setHessianIndex(int ti)
set the temporary index of the vertex in the parameter blocks
Generic interface for a non-linear solver operating on a graph.
Container that stores unique elements in no particular order, and which allow for fast retrieval or i...
Definition Set.h:59
uint04 size() const
Returns the number of elements in the Set.
Definition Set.h:158
Sparse optimizer that manages active vertices and edges for graph-based optimization.
g_type activeChi2() const
Returns the total chi-squared error of all active edges.
void push() final override
Remove a vertex.
const VertexContainer & indexMapping() const
the index mapping of the vertices
void update(const g_type *update)
update the estimate of the active vertices
void pop(Set< HyperGraph::HGVertex * > &vlist) final override
pop (restore) the estimate a subset of the variables from the stack
void discardTop() final override
discard the last backup of the estimate for all variables by removing it from the stack
OGVertex * findGauge()
Finds a gauge vertex (first vertex with maximum dimension) for fixing.
void computeActiveErrors()
computes the error vectors of all edges in the activeSet, and caches them
bool * _forceStopFlag
External flag to force stopping the optimization.
OGVertex *const * findActiveVertex(const OGVertex *v) const
Finds an active vertex by pointer using binary search.
void pop() final override
pop (restore) the estimate of all variables from the stack
void sortVectorContainers()
Sorts active vertices and edges by their ID comparators for deterministic ordering.
void setForceStopFlag(bool *flag)
sets a variable checked at every iteration to force a user stop.
bool initializeOptimization(int level=0)
Initializes the structures for optimizing a portion of the graph specified by a subset of vertices.
VertexContainer _activeVertices
Active vertices, sorted by VertexIDCompare.
VertexContainer _ivMap
Index-to-vertex mapping for the Hessian.
bool isReadyToUpdate() const
Returns true if the index mapping has been built and the optimizer is ready.
void linearizeSystem()
Linearizes the system by computing the Jacobians for the nodes and edges in the graph.
bool initializeOptimization(Set< HyperGraph::HGVertex * > &eset)
Initializes optimization from a specific edge set.
bool gaugeFreedom()
Returns true if the graph has gauge freedom (no fixed vertex of maximum dimension).
void push(Set< HyperGraph::HGVertex * > &vlist) final override
push the estimate of a subset of the variables onto a stack
void clear() final override
Clears all internal structures and the base graph.
void clearIndexMapping()
Clears the index mapping, resetting all vertex Hessian indices to -1.
OptimizableGraph::OGEdge *const * findActiveEdge(const OptimizableGraph::OGEdge *e) const
Finds an active edge by pointer using binary search.
EdgeContainer _activeEdges
Active edges, sorted by EdgeIDCompare.
g_type activeRobustChi2() const
Returns the total robustified chi-squared error of all active edges.
bool terminate()
if external stop flag is given, return its state. False otherwise
const VertexContainer & activeVertices() const
the vertices active in the current optimization
bool buildIndexMapping(SparseOptimizer::VertexContainer &vlist)
Builds the index mapping from active vertices to Hessian positions.
bool * forceStopFlag() const
Returns the external force-stop flag pointer.
const EdgeContainer & activeEdges() const
the edges active in the current optimization
The primary namespace for the NDEVR SDK.
constexpr t_type getMax(const t_type &left, const t_type &right)
Finds the max of the given arguments using the > operator The only requirement is that t_type have > ...
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
int32_t sint04
-Defines an alias representing a 4 byte, signed integer.
constexpr t_to cast(const Angle< t_from > &value)
Casts an Angle from one backing type to another.
Definition Angle.h:408
order edges based on the internal ID, which is assigned to the edge in addEdge()
order vertices based on their ID
OptimizableGraph()
empty constructor
JacobianWorkspace _jacobianWorkspace
Workspace for computing Jacobians.
Buffer< OptimizableGraph::OGVertex * > VertexContainer
vector container for vertices
Buffer< OptimizableGraph::OGEdge * > EdgeContainer
vector container for edges
@ AT_NUM_ELEMENTS
Sentinel value; keep as last element.