NDEVR
API Documentation
base_multi_edge.h
1#pragma once
2#include <iomanip>
3#include <limits>
4#include <NDEVR/Matrix.h>
5#include <Eigen/StdVector>
6
7#include "base_edge.h"
8#include "robust_kernel.h"
9
10namespace NDEVR
11{
12 using namespace Eigen;
13
20 template <sint04 t_dims, typename E>
21 class BaseMultiEdge : public BaseEdge<t_dims, E>
22 {
23 public:
27 struct HessianHelper {
28 Eigen::Map<MatrixX<g_type>> matrix;
30 HessianHelper()
31 : matrix(0, 0, 0)
32 , transposed(false)
33 {}
34 };
35
36 public:
39 typedef MatrixX<g_type>::MapType JacobianType;
42 typedef Eigen::Map<MatrixX<g_type>, MatrixX<g_type>::Flags & Eigen::PacketAccessBit
43 ? Eigen::Aligned
44 : Eigen::Unaligned> HessianBlockType;
45
48 : BaseEdge<t_dims, E>()
49 {}
50
51 virtual uint04 vertexCount() const final override { return _vertices.size(); };
53 virtual const HyperGraph::HGVertex* vertex(uint04 i) const final override { return _vertices[i]; };
55 virtual HyperGraph::HGVertex* vertex(uint04 i) final override { return _vertices[i]; };
59 virtual void setVertex(uint04 i, HyperGraph::HGVertex* v) final override
60 {
61 lib_assert(i < _vertices.size(), "index out of bounds");
62 lib_assert(dynamic_cast<OptimizableGraph::OGVertex*>(v) != nullptr, "invalid vertex type");
64 };
65
66
70 static inline int computeUpperTriangleIndex(int i, int j)
71 {
72 int elemsUpToCol = ((j - 1) * j) / 2;
73 return elemsUpToCol + i;
74 }
75
91
92
93 void linearizeOplusAndConstructQuadraticForm(JacobianWorkspace& jacobianWorkspace) final override
94 {
95 for (uint04 i = 0; i < _vertices.size(); ++i)
96 {
98 lib_assert(jacobianWorkspace.maxNumVertices() > i, "Bad vertex size");
99 lib_assert(jacobianWorkspace.maxDimension() >= cast<uint04>(t_dims * v->dimension()), "Bad vertex dimension");
100 new (&_jacobianOplus[i]) JacobianType(jacobianWorkspace.workspaceForVertex(i), t_dims, v->dimension());
101 }
102 linearizeOplus();
104 }
105
106 virtual void linearizeOplus()
107 {
108 const g_type delta = g_type(1e-9);
109 const g_type scalar = g_type(1.0) / (2 * delta);
110 ErrorVector errorBak;
111 ErrorVector errorBeforeNumeric = _error;
112 g_type add_vi[16];
113 for (uint04 i = 0; i < _vertices.size(); ++i)
114 {
115 //Xi - estimate the jacobian numerically
117
118 if (vi->fixed())
119 continue;
120
121 const int vi_dim = vi->dimension();
122 assert(vi_dim >= 0);
123 lib_assert(vi_dim < 16, "not enough memory");
124 std::fill(add_vi, add_vi + vi_dim, g_type(0.0));
125 lib_assert(_jacobianOplus[i].rows() == t_dims && _jacobianOplus[i].cols() == vi_dim, "jacobian cache dimension does not match");
126 _jacobianOplus[i].resize(Dimension, vi_dim);
127 // add small step along the unit vector in each dimension
128 for (int d = 0; d < vi_dim; ++d) {
129 vi->push();
130 add_vi[d] = delta;
131 vi->oplus(add_vi);
132 this->computeError();
133 errorBak = _error;
134 vi->pop();
135 vi->push();
136 add_vi[d] = -delta;
137 vi->oplus(add_vi);
138 this->computeError();
139 errorBak -= _error;
140 vi->pop();
141 add_vi[d] = 0.0;
142 //if ((scalar * errorBak).array().isNaN().any())
143 //throw "waht";
144 _jacobianOplus[i].col(d) = scalar * errorBak;
145 } // end dimension
146 }
147 _error = errorBeforeNumeric;
148 //if (!_error.array().isFinite().all())
149 //throw "error";
150 }
151
152 void mapHessianMemory(g_type* d, int i, int j, bool rowMajor) final override
153 {
154 int idx = computeUpperTriangleIndex(i, j);
155 assert(idx < (int)_hessian.size());
158 HessianHelper& h = _hessian[idx];
159 if (rowMajor)
160 {
161 if (h.matrix.data() != d || h.transposed != rowMajor)
162 new (&h.matrix) HessianBlockType(d, vj->dimension(), vi->dimension());
163 }
164 else
165 {
166 if (h.matrix.data() != d || h.transposed != rowMajor)
167 new (&h.matrix) HessianBlockType(d, vi->dimension(), vj->dimension());
168 }
169 h.transposed = rowMajor;
170 }
171
174 void resize(uint04 size)
175 {
176 lib_assert(false, "check this");
177 _vertices.resize(size);
178 if (size > 0)
179 {
180 uint04 n = _vertices.size();
181 uint04 maxIdx = (n * (n - 1)) / 2;
182 _hessian.setSize(maxIdx, HessianHelper());
183 _jacobianOplus.setSize(size, JacobianType(0, 0, 0));
184 }
185 else
186 {
187 _hessian.clear();
188 _jacobianOplus.clear();
189 }
190
191 }
192
194 bool allVerticesFixed() const final override
195 {
196 for (uint04 i = 0; i < _vertices.size(); ++i)
197 {
198 if (!_vertices[i]->fixed())
199 return false;
200 }
201 return true;
202 }
203
207 void computeQuadraticForm(const InformationType& omega, const ErrorVector& weightedError)
208 {
209 for (uint04 i = 0; i < _vertices.size(); ++i)
210 {
212 if (from->fixed())
213 continue;
214 const MatrixX<g_type>& A = _jacobianOplus[i];
215 MatrixX<g_type> AtO = A.transpose() * omega;
216 int fromDim = from->dimension();
217 lib_assert(fromDim >= 0, "Dimension");
218 Eigen::Map<MatrixX<g_type>> fromMap(from->hessianData(), fromDim, fromDim);
219 Eigen::Map<VectorX<g_type>> fromB(from->bData(), fromDim);
220
221 // ii block in the hessian
222 fromMap.noalias() += AtO * A;
223 fromB.noalias() += A.transpose() * weightedError;
224
225 // compute the off-diagonal blocks ij for all j
226 for (uint04 j = i + 1; j < _vertices.size(); ++j)
227 {
229 bool jstatus = !(to->fixed());
230 if (jstatus)
231 {
232 const MatrixX<g_type>& B = _jacobianOplus[j];
233 int idx = computeUpperTriangleIndex(i, j);
234 assert(idx < (int)_hessian.size());
235 HessianHelper& hhelper = _hessian[idx];
236 if (hhelper.transposed) // we have to write to the block as transposed
237 hhelper.matrix.noalias() += B.transpose() * AtO.transpose();
238 else
239 hhelper.matrix.noalias() += AtO * B;
240 //if (hhelper.matrix.array().isNaN().any())
241 //throw "waht";
242 }
243 }
244 }
245 }
246 protected:
247 using BaseEdge<t_dims, E>::_information;
248 using BaseEdge<t_dims, E>::_error;
250
253
254 public:
255 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
256 };
257
258}
g_type chi2() const final override
Computes the chi-squared error: e^T * Omega * e.
Definition base_edge.h:37
BaseEdge()
Default constructor.
Definition base_edge.h:25
InformationType robustInformation(const Eigen::Vector3< g_type > &rho) const
calculate the robust information matrix by updating the information matrix of the error
Definition base_edge.h:81
static constexpr sint04 Dimension
Compile-time dimension of the error vector.
Definition base_edge.h:19
InformationType _information
The information (inverse covariance) matrix.
Definition base_edge.h:74
Eigen::Matrix< g_type, t_dims, t_dims > InformationType
Fixed-size information (inverse covariance) matrix type.
Definition base_edge.h:22
const ErrorVector & error() const
Returns a const reference to the error vector.
Definition base_edge.h:43
ErrorVector _error
The current error vector.
Definition base_edge.h:76
Eigen::Matrix< g_type, t_dims, 1 > ErrorVector
Fixed-size error vector type.
Definition base_edge.h:21
E Measurement
The measurement type stored by this edge.
Definition base_edge.h:20
bool allVerticesFixed() const final override
Returns true if all connected vertices are fixed.
BaseEdge< t_dims, E >::ErrorVector ErrorVector
The error vector type.
void mapHessianMemory(g_type *d, int i, int j, bool rowMajor) final override
maps the internal matrix to some external memory location, you need to provide the memory before call...
Buffer< HessianHelper > _hessian
Off-diagonal Hessian blocks (upper triangle).
virtual uint04 vertexCount() const final override
Returns the number of connected vertices.
void linearizeOplusAndConstructQuadraticForm(JacobianWorkspace &jacobianWorkspace) final override
Linearizes the constraint in the edge in the manifold space, and store the result in the given worksp...
MatrixX< g_type >::MapType JacobianType
Dynamic-size Jacobian map type.
Buffer< OptimizableGraph::OGVertex * > _vertices
The connected vertices.
static const int Dimension
Dimension of the error vector.
virtual const HyperGraph::HGVertex * vertex(uint04 i) const final override
Returns a const pointer to the i-th vertex.
virtual void setVertex(uint04 i, HyperGraph::HGVertex *v) final override
Sets the i-th vertex, with bounds and type checking.
void resize(uint04 size)
Resizes the edge to connect a given number of vertices.
Buffer< JacobianType > _jacobianOplus
jacobians of the edge (w.r.t. oplus)
static int computeUpperTriangleIndex(int i, int j)
Computes the linear index for the upper-triangular storage of off-diagonal Hessian blocks.
BaseEdge< t_dims, E >::InformationType InformationType
The information matrix type.
BaseMultiEdge()
Default constructor.
virtual HyperGraph::HGVertex * vertex(uint04 i) final override
Returns a mutable pointer to the i-th vertex.
void computeQuadraticForm(const InformationType &omega, const ErrorVector &weightedError)
Computes the quadratic form contributions for all vertex pairs.
void constructQuadraticForm()
Constructs the quadratic form (Hessian and gradient) from the linearized multi-edge.
BaseEdge< t_dims, E >::Measurement Measurement
The measurement type.
The equivelent of std::vector but with a bit more control.
Definition Buffer.hpp:58
abstract Vertex, your types must derive from that one
Definition hyper_graph.h:28
provide memory workspace for computing the Jacobians
virtual void computeError()=0
Computes the error of the edge and stores it internally.
RobustKernel * robustKernel() const
if NOT NULL, error of this edge will be robustifed with the kernel
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
virtual g_type * bData()=0
return a pointer to the b vector associated with this vertex
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
virtual void robustify(g_type squaredError, Eigen::Vector3< g_type > &rho) const =0
compute the scaling factor for a error: The error is e^T Omega e The output rho is rho[0]: The actual...
The primary namespace for the NDEVR SDK.
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
constexpr t_to cast(const Angle< t_from > &value)
Casts an Angle from one backing type to another.
Definition Angle.h:408
helper for mapping the Hessian memory of the upper triangular block
Eigen::Map< MatrixX< g_type > > matrix
the mapped memory
bool transposed
the block has to be transposed