NDEVR
API Documentation
base_unary_edge.h
1#pragma once
2#include <cassert>
3#include <limits>
4
5#include "base_edge.h"
6#include "robust_kernel.h"
7
8namespace NDEVR
9{
10
11 using namespace Eigen;
12
20 template <sint04 t_dims, typename E, typename VertexXi>
21 class BaseUnaryEdge : public BaseEdge<t_dims, E>
22 {
23 public:
25 typedef VertexXi VertexXiType;
26 typedef typename Eigen::Matrix<g_type, t_dims, VertexXiType::Dimension>::AlignedMapType JacobianXiOplusType;
29
32 : BaseEdge<t_dims, E>()
34 {}
35
36 virtual uint04 vertexCount() const final override { return 1; };
38 virtual const HyperGraph::HGVertex* vertex(uint04) const final override { return m_vertex; };
40 virtual HyperGraph::HGVertex* vertex(uint04) final override { return m_vertex; };
43 virtual void setVertex(uint04, HyperGraph::HGVertex* v) final override
44 {
45 lib_assert(dynamic_cast<VertexXiType*>(v), "wrong type");
47 };
48
50 virtual bool allVerticesFixed() const final override
51 {
52 return m_vertex->fixed();
53 }
54
56 virtual void linearizeOplusAndConstructQuadraticForm(JacobianWorkspace& jacobianWorkspace) final override
57 {
58 lib_assert(jacobianWorkspace.maxNumVertices() >= 1, "Bad vertex size");
59 lib_assert(jacobianWorkspace.maxDimension() >= t_dims * VertexXiType::Dimension, "Bad vertex dimension");
60
61 new (&_jacobianOplusXi) JacobianXiOplusType(jacobianWorkspace.workspaceForVertex(0), t_dims, VertexXiType::Dimension);
63 //VertexXiType* from = static_cast<VertexXiType*>(_vertices[0]);
64 /*auto b = from->b();
65 auto H = from->A();
66 constructQuadraticForm2();
67 auto ba = from->b();
68 auto Ha = from->A();
69 from->b() = b;
70 from->A() = H;*/
72 //lib_assert(ba.isApprox(from->b(), 1e-6), "Bad b match");
73 //lib_assert(Ha.isApprox(from->A(), 1e-6), "Bad A match");
74 }
75
76
81 virtual void linearizeOplus()
82 {
83 //Xi - estimate the jacobian numerically
85
86 if (vi->fixed())
87 return;
88 constexpr g_type delta = g_type(1e-9);
89 constexpr g_type scalar = g_type(1.0) / (2 * delta);
90 ErrorVector error1;
91 ErrorVector errorBeforeNumeric = _error;
92
93 g_type add_vi[VertexXiType::Dimension];
94 std::fill(add_vi, add_vi + VertexXiType::Dimension, g_type(0.0));
95 // add small step along the unit vector in each dimension
96 for (int d = 0; d < VertexXiType::Dimension; ++d)
97 {
98 vi->push();
99 add_vi[d] = delta;
100 vi->oplus(add_vi);
101 computeError();
102 error1 = _error;
103 vi->pop();
104 vi->push();
105 add_vi[d] = -delta;
106 vi->oplus(add_vi);
107 computeError();
108 vi->pop();
109 add_vi[d] = 0.0;
110 //if (scalar * (error1 - _error).array().isNaN().any())
111 //throw "waht";
112 _jacobianOplusXi.col(d) = scalar * (error1 - _error);
113 } // end dimension
114
115 _error = errorBeforeNumeric;
116 //if (!_error.array().isFinite().all())
117 //throw "error";
118 }
119
124 {
125 if (m_vertex->fixed())
126 return;
127 const JacobianXiOplusType& A = jacobianOplusXi(); // Fixed-size matrix
128 const InformationType& omega = BaseEdge<t_dims, E>::information(); // Symmetric 3×3
129 auto& b = m_vertex->b();
130 auto& H = m_vertex->A();
131
132 // Cache transpose and error product
133 const auto A_trans = A.transpose();
134 const auto omega_e = omega.selfadjointView<Eigen::Upper>() * _error;
135
136 if (auto* kernel = BaseEdge<t_dims, E>::robustKernel())
137 {
138 Eigen::Vector3<g_type> rho;
139 kernel->robustify(BaseEdge<t_dims, E>::chi2(), rho);
140
141 const g_type w = rho[1];
142 EIGEN_ALIGN32 InformationType weighted_omega = BaseEdge<t_dims, E>::robustInformation(rho);
143
144 //if ((w * A_trans * omega_e).array().isNaN().any())
145 //throw "waht";
146 // Fast right-hand side update
147 b.noalias() -= w * A_trans * omega_e;
148
149 // Hessian update: exploit symmetry
150 H.noalias() += A_trans * weighted_omega.selfadjointView<Eigen::Upper>() * A;
151 //if (H.array().isNaN().any())
152 //throw "waht";
153 }
154 else
155 {
156 b.noalias() -= A_trans * omega_e;
157 //if (H.array().isNaN().any())
158 //throw "waht";
159 H.noalias() += A_trans * omega.selfadjointView<Eigen::Upper>() * A;
160 //if (H.array().isNaN().any())
161 //throw "waht";
162 }
163 }
164 /*void constructQuadraticForm2()
165 {
166 VertexXiType* from = static_cast<VertexXiType*>(_vertices[0]);
167
168 // chain rule to get the Jacobian of the nodes in the manifold domain
169 const JacobianXiOplusType& A = jacobianOplusXi();
170 const InformationType& omega = BaseEdge<t_dims, E>::information();
171 if (!from->fixed())
172 {
173 if (BaseEdge<t_dims, E>::robustKernel())
174 {
175 g_type error = BaseEdge<t_dims, E>::chi2();
176 Eigen::Vector3<g_type> rho;
177 BaseEdge<t_dims, E>::robustKernel()->robustify(error, rho);
178 EIGEN_ALIGN32 InformationType weighted_omega = BaseEdge<t_dims, E>::robustInformation(rho);
179 from->b().noalias() -= rho[1] * A.transpose() * omega * _error;
180 from->A().noalias() += A.transpose() * weighted_omega * A;
181 }
182 else
183 {
184 from->b().noalias() -= A.transpose() * omega * _error;
185 from->A().noalias() += A.transpose() * omega * A;
186 }
187 }
188 }*/
189 virtual void mapHessianMemory(g_type*, int, int, bool) final override { lib_assert(false, "BaseUnaryEdge does not map memory of the Hessian"); }
190
191 using BaseEdge<t_dims, E>::computeError;
192
193 protected:
195 using BaseEdge<t_dims, E>::_measurement;
196 using BaseEdge<t_dims, E>::_error;
197
199
200 public:
201 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
202 };
203
204}
Base class for edges with a fixed-size error vector and measurement type.
Definition base_edge.h:17
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
Eigen::Matrix< g_type, t_dims, t_dims > InformationType
Fixed-size information (inverse covariance) matrix type.
Definition base_edge.h:22
const InformationType & information() const
Returns a const reference to the information matrix.
Definition base_edge.h:50
Measurement _measurement
The stored measurement for this edge.
Definition base_edge.h:75
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
void constructQuadraticForm()
Constructs the quadratic form (Hessian block and gradient) for this unary edge.
BaseUnaryEdge()
Default constructor.
virtual HyperGraph::HGVertex * vertex(uint04) final override
Returns a mutable pointer to the single vertex.
virtual void linearizeOplusAndConstructQuadraticForm(JacobianWorkspace &jacobianWorkspace) final override
Linearizes the oplus operator and constructs the quadratic form.
virtual const HyperGraph::HGVertex * vertex(uint04) const final override
Returns a const pointer to the single vertex.
virtual uint04 vertexCount() const final override
Returns the number of vertices (always 1 for unary edges).
BaseEdge< t_dims, E >::Measurement Measurement
The measurement type.
VertexXi VertexXiType
The vertex type.
VertexXiType * m_vertex
Pointer to the connected vertex.
BaseEdge< t_dims, E >::ErrorVector ErrorVector
The error vector type.
Eigen::Matrix< g_type, t_dims, VertexXiType::Dimension >::AlignedMapType JacobianXiOplusType
Jacobian type w.r.t. the vertex.
virtual void setVertex(uint04, HyperGraph::HGVertex *v) final override
Sets the vertex, with type-checking.
BaseEdge< t_dims, E >::InformationType InformationType
The information matrix type.
virtual void linearizeOplus()
Linearizes the oplus operator in the vertex, and stores the result in temporary variables _jacobianOp...
virtual void mapHessianMemory(g_type *, int, int, bool) final override
maps the internal matrix to some external memory location, you need to provide the memory before call...
const JacobianXiOplusType & jacobianOplusXi() const
returns the result of the linearization in the manifold space for the node xi
JacobianXiOplusType _jacobianOplusXi
Jacobian of the error w.r.t. the vertex.
virtual bool allVerticesFixed() const final override
Returns true if the single vertex is fixed.
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
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