Main MRPT website > C++ reference for MRPT 1.9.9
ScalarFactorGraph.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "graphs-precomp.h" // Precompiled headers
11 
13 #include <mrpt/utils/CTicTac.h>
14 
15 using namespace mrpt;
16 using namespace mrpt::graphs;
17 using namespace mrpt::utils;
18 using namespace std;
19 
20 #if EIGEN_VERSION_AT_LEAST(3, 1, 0) // Requires Eigen>=3.1
21 #include <Eigen/SparseCore>
22 #include <Eigen/SparseQR>
23 #endif
24 
27  : COutputLogger("GMRF"), m_enable_profiler(false)
28 {
29 }
30 
32 {
33  MRPT_LOG_DEBUG("clear() called");
34 
35  m_numNodes = 0;
36  m_factors_unary.clear();
37  m_factors_binary.clear();
38 }
39 
40 void ScalarFactorGraph::initialize(const size_t nodeCount)
41 {
42  MRPT_LOG_DEBUG_STREAM("initialize() called, nodeCount=" << nodeCount);
43 
44  m_numNodes = nodeCount;
45 }
46 
48 {
49  m_factors_unary.push_back(&c);
50 }
52 {
53  m_factors_binary.push_back(&c);
54 }
55 
57 {
58  {
59  auto it = std::find(m_factors_unary.begin(), m_factors_unary.end(), &c);
60  if (it != m_factors_unary.end())
61  {
62  m_factors_unary.erase(it);
63  return true;
64  }
65  }
66  {
67  auto it =
68  std::find(m_factors_binary.begin(), m_factors_binary.end(), &c);
69  if (it != m_factors_binary.end())
70  {
71  m_factors_binary.erase(it);
72  return true;
73  }
74  }
75  return false;
76 }
77 
78 /* Method:
79  (\Sigma)^{-1/2) * d( h(x) )/d( x ) * x_incr = - (\Sigma)^{-1/2) * r(x)
80  =================================== ========================
81  =A =b
82 
83  A * x_incr = b --> SparseQR.
84 */
86  /** Output increment of the current estimate. Caller must add this
87  vector to current state vector to obtain the optimal estimation. */
88  Eigen::VectorXd& solved_x_inc,
89  /** If !=nullptr, the covariance of the estimate will be stored here. */
90  Eigen::VectorXd* solved_variances)
91 {
92  ASSERTMSG_(m_numNodes > 0, "numNodes=0. Have you called initialize()?");
93 
95 
96 #if EIGEN_VERSION_AT_LEAST(3, 1, 0)
97 
98  // Number of vertices:
99  const size_t n = m_numNodes;
100  solved_x_inc.setZero(n);
101 
102  // Number of edges:
103  const size_t m1 = m_factors_unary.size(), m2 = m_factors_binary.size();
104  const size_t m = m1 + m2;
105 
106  // Build Ax=b
107  // -----------------------
108  m_timelogger.enter("GMRF.build_A_tri");
109 
110  std::vector<Eigen::Triplet<double>> A_tri;
111  A_tri.reserve(m1 + 2 * m2);
112 
113  Eigen::VectorXd g; // Error vector
114 
115  g.setZero(m);
116  int edge_counter = 0;
117  for (const auto& e : m_factors_unary)
118  {
119  ASSERT_(e != nullptr);
120  // Jacob:
121  const double w = std::sqrt(e->getInformation());
122  double dr_dx;
123  e->evalJacobian(dr_dx);
124  const int node_id = e->node_id;
125  A_tri.push_back(
126  Eigen::Triplet<double>(edge_counter, node_id, w * dr_dx));
127  // gradient:
128  g[edge_counter] -= w * e->evaluateResidual();
129 
130  ++edge_counter;
131  }
132  for (const auto& e : m_factors_binary)
133  {
134  ASSERT_(e != nullptr);
135  // Jacob:
136  const double w = std::sqrt(e->getInformation());
137  double dr_dxi, dr_dxj;
138  e->evalJacobian(dr_dxi, dr_dxj);
139  const int node_id_i = e->node_id_i, node_id_j = e->node_id_j;
140  A_tri.push_back(
141  Eigen::Triplet<double>(edge_counter, node_id_i, w * dr_dxi));
142  A_tri.push_back(
143  Eigen::Triplet<double>(edge_counter, node_id_j, w * dr_dxj));
144  // gradient:
145  g[edge_counter] -= w * e->evaluateResidual();
146 
147  ++edge_counter;
148  }
149  m_timelogger.leave("GMRF.build_A_tri");
150 
151  // Compress sparse
152  // -----------------------
153  Eigen::SparseMatrix<double> A(m, n);
154  {
156  m_timelogger, "GMRF.build_A_compress");
157 
158  A.setFromTriplets(A_tri.begin(), A_tri.end());
159  A.makeCompressed();
160  }
161 
162  // Solve increment
163  // -----------------------
164  Eigen::SparseQR<Eigen::SparseMatrix<double>, Eigen::COLAMDOrdering<int>>
165  solver;
166  {
167  mrpt::utils::CTimeLoggerEntry tle(m_timelogger, "GMRF.solve");
168 
169  solver.compute(A);
170  solved_x_inc = solver.solve(g);
171  }
172 
173  // Recover covariance
174  // -----------------------
175  if (solved_variances)
176  {
177  mrpt::utils::CTimeLoggerEntry tle(m_timelogger, "GMRF.variance");
178 
179  solved_variances->resize(n);
180 
181  // VARIANCE SIGMA = inv(P) * inv( P*H*inv(P) ) * P
182  // Get triangular supperior P*H*inv(P) = UT' * UT = P * R'*R * inv(P)
183  // (QR factor: Use UT=R)
184 
185  MRPT_TODO("Use compressed access instead of coeff() below");
186 
187  Eigen::SparseMatrix<double> UT = solver.matrixR();
188  Eigen::SparseMatrix<double> solved_covariance(n, n);
189  solved_covariance.reserve(UT.nonZeros());
190 
191  // Apply custom equations to obtain the inverse -> inv( P*H*inv(P) )
192  const int show_progress_steps = std::max(int(20), int(n / 20));
193  for (int l = n - 1; l >= 0; l--)
194  {
195  if (!(l % show_progress_steps))
197  "Computing variance %6.02f%%... \r",
198  (100.0 * (n - l - 1)) / n);
199 
200  // Computes variances in the inferior submatrix of "l"
201  double subSigmas = 0.0;
202  for (size_t j = l + 1; j < n; j++)
203  {
204  if (UT.coeff(l, j) != 0)
205  {
206  // Compute off-diagonal variances Sigma(j,l) = Sigma(l,j);
207 
208  // SUM 1
209  double sum = 0.0;
210  for (size_t i = l + 1; i <= j; i++)
211  {
212  if (UT.coeff(l, i) != 0)
213  {
214  sum +=
215  UT.coeff(l, i) * solved_covariance.coeff(i, j);
216  }
217  }
218  // SUM 2
219  for (size_t i = j + 1; i < n; ++i)
220  {
221  if (UT.coeff(l, i) != 0)
222  {
223  sum +=
224  UT.coeff(l, i) * solved_covariance.coeff(j, i);
225  }
226  }
227  // Save off-diagonal variance (only Upper triangular)
228  solved_covariance.insert(l, j) = (-sum / UT.coeff(l, l));
229  subSigmas += UT.coeff(l, j) * solved_covariance.coeff(l, j);
230  }
231  }
232 
233  solved_covariance.insert(l, l) =
234  (1 / UT.coeff(l, l)) * (1 / UT.coeff(l, l) - subSigmas);
235  }
236 
237  MRPT_LOG_DEBUG_FMT("Computing variance %6.02f%%... \r", 100.0);
238 
239  for (unsigned int i = 0; i < n; i++)
240  {
241  const int idx = (int)solver.colsPermutation().indices().coeff(i);
242  const double variance = solved_covariance.coeff(i, i);
243  (*solved_variances)[idx] = variance;
244  }
245 
246  } // end calc variances
247 
248 #else
249  THROW_EXCEPTION("This method requires Eigen 3.1.0 or above")
250 #endif
251 }
void initialize(const size_t nodeCount)
Initialize the GMRF internal state and copy the prior factors.
Simple, scalar (1-dim) constraint (edge) for a GMRF.
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
bool eraseConstraint(const FactorBase &c)
Removes a constraint.
#define THROW_EXCEPTION(msg)
Abstract graph and tree data structures, plus generic graph algorithms.
#define MRPT_LOG_DEBUG_FMT(_FMT_STRING,...)
GLenum GLsizei n
Definition: glext.h:5074
std::deque< const BinaryFactorVirtualBase * > m_factors_binary
STL namespace.
const_iterator find(const KEY &key) const
Definition: ts_hash_map.h:220
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:4178
#define MRPT_TODO(x)
void enable(bool enabled=true)
Definition: CTimeLogger.h:107
std::deque< const UnaryFactorVirtualBase * > m_factors_unary
const GLubyte * c
Definition: glext.h:6313
CONTAINER::Scalar sum(const CONTAINER &v)
Computes the sum of all the elements.
GLubyte g
Definition: glext.h:6279
mrpt::utils::CTimeLogger m_timelogger
#define MRPT_LOG_DEBUG(_STRING)
void addConstraint(const UnaryFactorVirtualBase &listOfConstraints)
Insert constraints into the GMRF problem.
size_t m_numNodes
number of nodes in the graph
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
A safe way to call enter() and leave() of a mrpt::utils::CTimeLogger upon construction and destructio...
Definition: CTimeLogger.h:152
#define ASSERT_(f)
double leave(const char *func_name)
End of a named section.
Definition: CTimeLogger.h:123
void clear()
Reset state: remove all constraints and nodes.
Simple, scalar (1-dim) constraint (edge) for a GMRF.
void enter(const char *func_name)
Start of a named section.
Definition: CTimeLogger.h:117
#define MRPT_LOG_DEBUG_STREAM(__CONTENTS)
#define ASSERTMSG_(f, __ERROR_MSG)
void updateEstimation(Eigen::VectorXd &solved_x_inc, Eigen::VectorXd *solved_variances=nullptr)



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019