gtsam  4.0.0
gtsam
ISAM2-inl.h
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------------
2 
3  * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4  * Atlanta, Georgia 30332-0415
5  * All Rights Reserved
6  * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7 
8  * See LICENSE for the license information
9 
10  * -------------------------------------------------------------------------- */
11 
20 #pragma once
21 
22 #include <stack>
25 
26 namespace gtsam {
27 
28 /* ************************************************************************* */
29 template<class VALUE>
30 VALUE ISAM2::calculateEstimate(Key key) const {
31  const Vector& delta = getDelta()[key];
32  return traits<VALUE>::Retract(theta_.at<VALUE>(key), delta);
33 }
34 
35 /* ************************************************************************* */
36 namespace internal {
37 template<class CLIQUE>
38 void optimizeWildfire(const boost::shared_ptr<CLIQUE>& clique, double threshold,
39  KeySet& changed, const KeySet& replaced, VectorValues& delta, size_t& count)
40 {
41  // if none of the variables in this clique (frontal and separator!) changed
42  // significantly, then by the running intersection property, none of the
43  // cliques in the children need to be processed
44 
45  // Are any clique variables part of the tree that has been redone?
46  bool cliqueReplaced = replaced.exists((*clique)->frontals().front());
47 #ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS
48  for(Key frontal: clique->conditional()->frontals()) {
49  assert(cliqueReplaced == replaced.exists(frontal));
50  }
51 #endif
52 
53  // If not redone, then has one of the separator variables changed significantly?
54  bool recalculate = cliqueReplaced;
55  if(!recalculate) {
56  for(Key parent: clique->conditional()->parents()) {
57  if(changed.exists(parent)) {
58  recalculate = true;
59  break;
60  }
61  }
62  }
63 
64  // Solve clique if it was replaced, or if any parents were changed above the
65  // threshold or themselves replaced.
66  if(recalculate) {
67 
68  // Temporary copy of the original values, to check how much they change
69  FastVector<Vector> originalValues(clique->conditional()->nrFrontals());
71  for(it = clique->conditional()->beginFrontals(); it!=clique->conditional()->endFrontals(); it++) {
72  originalValues[it - clique->conditional()->beginFrontals()] = delta[*it];
73  }
74 
75  // Back-substitute
76  delta.update(clique->conditional()->solve(delta));
77  count += clique->conditional()->nrFrontals();
78 
79  // Whether the values changed above a threshold, or always true if the
80  // clique was replaced.
81  bool valuesChanged = cliqueReplaced;
82  for(it = clique->conditional()->beginFrontals(); it != clique->conditional()->endFrontals(); it++) {
83  if(!valuesChanged) {
84  const Vector& oldValue(originalValues[it - clique->conditional()->beginFrontals()]);
85  const Vector& newValue(delta[*it]);
86  if((oldValue - newValue).lpNorm<Eigen::Infinity>() >= threshold) {
87  valuesChanged = true;
88  break;
89  }
90  } else
91  break;
92  }
93 
94  // If the values were above the threshold or this clique was replaced
95  if(valuesChanged) {
96  // Set changed flag for each frontal variable and leave the new values
97  for(Key frontal: clique->conditional()->frontals()) {
98  changed.insert(frontal);
99  }
100  } else {
101  // Replace with the old values
102  for(it = clique->conditional()->beginFrontals(); it != clique->conditional()->endFrontals(); it++) {
103  delta[*it] = originalValues[it - clique->conditional()->beginFrontals()];
104  }
105  }
106 
107  // Recurse to children
108  for(const typename CLIQUE::shared_ptr& child: clique->children) {
109  optimizeWildfire(child, threshold, changed, replaced, delta, count);
110  }
111  }
112 }
113 
114 template<class CLIQUE>
115 bool optimizeWildfireNode(const boost::shared_ptr<CLIQUE>& clique, double threshold,
116  KeySet& changed, const KeySet& replaced, VectorValues& delta, size_t& count)
117 {
118  // if none of the variables in this clique (frontal and separator!) changed
119  // significantly, then by the running intersection property, none of the
120  // cliques in the children need to be processed
121 
122  // Are any clique variables part of the tree that has been redone?
123  bool cliqueReplaced = replaced.exists(clique->conditional()->frontals().front());
124 #ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS
125  for(Key frontal: clique->conditional()->frontals()) {
126  assert(cliqueReplaced == replaced.exists(frontal));
127  }
128 #endif
129 
130  // If not redone, then has one of the separator variables changed significantly?
131  bool recalculate = cliqueReplaced;
132  if(!recalculate) {
133  for(Key parent: clique->conditional()->parents()) {
134  if(changed.exists(parent)) {
135  recalculate = true;
136  break;
137  }
138  }
139  }
140 
141  // Solve clique if it was replaced, or if any parents were changed above the
142  // threshold or themselves replaced.
143  // TODO(gareth): This code shares a lot of logic w/ linearAlgorithms-inst, potentially refactor
144  if(recalculate)
145  {
146  // Temporary copy of the original values, to check how much they change
147  FastVector<Vector> originalValues(clique->conditional()->nrFrontals());
149  for(it = clique->conditional()->beginFrontals(); it != clique->conditional()->endFrontals(); it++) {
150  originalValues[it - clique->conditional()->beginFrontals()] = delta[*it];
151  }
152 
153  // Back-substitute - special version stores solution pointers in cliques for fast access.
154  {
155  // Create solution part pointers if necessary and possible - necessary if solnPointers_ is
156  // empty, and possible if either we're a root, or we have a parent with valid solnPointers_.
157  boost::shared_ptr<CLIQUE> parent = clique->parent_.lock();
158  if(clique->solnPointers_.empty() && (clique->isRoot() || !parent->solnPointers_.empty()))
159  {
160  for(Key key: clique->conditional()->frontals())
161  clique->solnPointers_.insert(std::make_pair(key, delta.find(key)));
162  for(Key key: clique->conditional()->parents())
163  clique->solnPointers_.insert(std::make_pair(key, parent->solnPointers_.at(key)));
164  }
165 
166  // See if we can use solution part pointers - we can if they either already existed or were
167  // created above.
168  if(!clique->solnPointers_.empty())
169  {
170  GaussianConditional& c = *clique->conditional();
171  // Solve matrix
172  Vector xS;
173  {
174  // Count dimensions of vector
175  DenseIndex dim = 0;
177  parentPointers.reserve(clique->conditional()->nrParents());
178  for(Key parent: clique->conditional()->parents()) {
179  parentPointers.push_back(clique->solnPointers_.at(parent));
180  dim += parentPointers.back()->second.size();
181  }
182 
183  // Fill parent vector
184  xS.resize(dim);
185  DenseIndex vectorPos = 0;
186  for(const VectorValues::const_iterator& parentPointer: parentPointers) {
187  const Vector& parentVector = parentPointer->second;
188  xS.block(vectorPos,0,parentVector.size(),1) = parentVector.block(0,0,parentVector.size(),1);
189  vectorPos += parentVector.size();
190  }
191  }
192 
193  // NOTE(gareth): We can no longer write: xS = b - S * xS
194  // This is because Eigen (as of 3.3) no longer evaluates S * xS into
195  // a temporary, and the operation trashes valus in xS.
196  // See: http://eigen.tuxfamily.org/index.php?title=3.3
197  const Vector rhs = c.getb() - c.get_S() * xS;
198  const Vector solution = c.get_R().triangularView<Eigen::Upper>().solve(rhs);
199 
200  // Check for indeterminant solution
201  if(solution.hasNaN()) throw IndeterminantLinearSystemException(c.keys().front());
202 
203  // Insert solution into a VectorValues
204  DenseIndex vectorPosition = 0;
205  for(GaussianConditional::const_iterator frontal = c.beginFrontals(); frontal != c.endFrontals(); ++frontal) {
206  clique->solnPointers_.at(*frontal)->second = solution.segment(vectorPosition, c.getDim(frontal));
207  vectorPosition += c.getDim(frontal);
208  }
209  }
210  else
211  {
212  // Just call plain solve because we couldn't use solution pointers.
213  delta.update(clique->conditional()->solve(delta));
214  }
215  }
216  count += clique->conditional()->nrFrontals();
217 
218  // Whether the values changed above a threshold, or always true if the
219  // clique was replaced.
220  bool valuesChanged = cliqueReplaced;
221  for(it = clique->conditional()->beginFrontals(); it != clique->conditional()->endFrontals(); it++) {
222  if(!valuesChanged) {
223  const Vector& oldValue(originalValues[it - clique->conditional()->beginFrontals()]);
224  const Vector& newValue(delta[*it]);
225  if((oldValue - newValue).lpNorm<Eigen::Infinity>() >= threshold) {
226  valuesChanged = true;
227  break;
228  }
229  } else
230  break;
231  }
232 
233  // If the values were above the threshold or this clique was replaced
234  if(valuesChanged) {
235  // Set changed flag for each frontal variable and leave the new values
236  for(Key frontal: clique->conditional()->frontals()) {
237  changed.insert(frontal);
238  }
239  } else {
240  // Replace with the old values
241  for(it = clique->conditional()->beginFrontals(); it != clique->conditional()->endFrontals(); it++) {
242  delta[*it] = originalValues[it - clique->conditional()->beginFrontals()];
243  }
244  }
245  }
246 
247  return recalculate;
248 }
249 
250 } // namespace internal
251 
252 /* ************************************************************************* */
253 template<class CLIQUE>
254 size_t optimizeWildfire(const boost::shared_ptr<CLIQUE>& root, double threshold, const KeySet& keys, VectorValues& delta) {
255  KeySet changed;
256  int count = 0;
257  // starting from the root, call optimize on each conditional
258  if(root)
259  internal::optimizeWildfire(root, threshold, changed, keys, delta, count);
260  return count;
261 }
262 
263 /* ************************************************************************* */
264 template<class CLIQUE>
265 size_t optimizeWildfireNonRecursive(const boost::shared_ptr<CLIQUE>& root, double threshold, const KeySet& keys, VectorValues& delta)
266 {
267  KeySet changed;
268  size_t count = 0;
269 
270  if (root) {
271  std::stack<boost::shared_ptr<CLIQUE> > travStack;
272  travStack.push(root);
273  boost::shared_ptr<CLIQUE> currentNode = root;
274  while (!travStack.empty()) {
275  currentNode = travStack.top();
276  travStack.pop();
277  bool recalculate = internal::optimizeWildfireNode(currentNode, threshold, changed, keys, delta, count);
278  if (recalculate) {
279  for(const typename CLIQUE::shared_ptr& child: currentNode->children) {
280  travStack.push(child);
281  }
282  }
283  }
284  }
285 
286  return count;
287 }
288 
289 /* ************************************************************************* */
290 template<class CLIQUE>
291 void nnz_internal(const boost::shared_ptr<CLIQUE>& clique, int& result) {
292  int dimR = (int)clique->conditional()->rows();
293  int dimSep = (int)clique->conditional()->get_S().cols();
294  result += ((dimR+1)*dimR)/2 + dimSep*dimR;
295  // traverse the children
296  for(const typename CLIQUE::shared_ptr& child: clique->children) {
297  nnz_internal(child, result);
298  }
299 }
300 
301 /* ************************************************************************* */
302 template<class CLIQUE>
303 int calculate_nnz(const boost::shared_ptr<CLIQUE>& clique) {
304  int result = 0;
305  // starting from the root, add up entries of frontal and conditional matrices of each conditional
306  nnz_internal(clique, result);
307  return result;
308 }
309 
310 }
311 
bool exists(const VALUE &e) const
Handy &#39;exists&#39; function.
Definition: FastSet.h:98
Values::const_iterator const_iterator
Const iterator over vector values.
Definition: VectorValues.h:98
int calculate_nnz(const boost::shared_ptr< CLIQUE > &clique)
calculate the number of non-zero entries for the tree starting at clique (use root for complete matri...
Definition: ISAM2-inl.h:303
FACTOR::const_iterator beginFrontals() const
Iterator pointing to first frontal key.
Definition: Conditional.h:104
const VectorValues & getDelta() const
Access the current delta, computed during the last call to update.
Definition: ISAM2.cpp:1040
Values theta_
The current linearization point.
Definition: ISAM2.h:440
A conditional Gaussian functions as the node in a Bayes network It has a set of parents y...
Definition: GaussianConditional.h:36
Factor Graph Base Class.
Thrown when a linear system is ill-posed.
Definition: linearExceptions.h:94
iterator find(Key j)
Return the iterator corresponding to the requested key, or end() if no variable is present with this ...
Definition: VectorValues.h:227
const constBVector getb() const
Get a view of the r.h.s.
Definition: JacobianFactor.h:264
FACTOR::const_iterator endFrontals() const
Iterator pointing past the last frontal key.
Definition: Conditional.h:107
Definition: FastVector.h:36
void update(const VectorValues &values)
For all key/value pairs in values, replace values with corresponding keys in this class with those in...
Definition: VectorValues.cpp:90
constABlock get_S() const
Get a view of the parent blocks.
Definition: GaussianConditional.h:100
ptrdiff_t DenseIndex
The index type for Eigen objects.
Definition: types.h:60
Values calculateEstimate() const
Compute an estimate from the incomplete linear delta computed during the last update.
Definition: ISAM2.cpp:1014
ValueType at(Key j) const
Retrieve a variable by key j.
Definition: Values-inl.h:343
This class represents a collection of vector-valued variables associated each with a unique integer i...
Definition: VectorValues.h:90
FastVector< Key >::const_iterator const_iterator
Const iterator over keys.
Definition: Factor.h:64
size_t optimizeWildfire(const boost::shared_ptr< CLIQUE > &root, double threshold, const KeySet &keys, VectorValues &delta)
Optimize the BayesTree, starting from the root.
Definition: ISAM2-inl.h:254
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition: concepts.h:30
const FastVector< Key > & keys() const
Access the factor&#39;s involved variable keys.
Definition: Factor.h:115
virtual DenseIndex getDim(const_iterator variable) const
Return the dimension of the variable pointed to by the given key iterator todo: Remove this in favor ...
Definition: JacobianFactor.h:245
constABlock get_R() const
Return a view of the upper-triangular R block of the conditional.
Definition: GaussianConditional.h:97
const sharedClique & clique(Key j) const
alternate syntax for matlab: find the clique that contains the variable with Key j ...
Definition: BayesTree.h:150
iterator insert(Key j, const Vector &value)
Insert a vector value with key j.
Definition: VectorValues.h:187
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:57
Global functions in a separate testing namespace.
Definition: chartTesting.h:28