gtsam  3.2.1
gtsam
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 theta_.at<VALUE>(key).retract(delta);
33 }
34 
35 /* ************************************************************************* */
36 namespace internal {
37 template<class CLIQUE>
38 void optimizeWildfire(const boost::shared_ptr<CLIQUE>& clique, double threshold,
39  FastSet<Key>& changed, const FastSet<Key>& 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  BOOST_FOREACH(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  BOOST_FOREACH(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  BOOST_FOREACH(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  BOOST_FOREACH(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  FastSet<Key>& changed, const FastSet<Key>& 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  BOOST_FOREACH(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  BOOST_FOREACH(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  if(recalculate)
144  {
145  // Temporary copy of the original values, to check how much they change
146  FastVector<Vector> originalValues(clique->conditional()->nrFrontals());
148  for(it = clique->conditional()->beginFrontals(); it != clique->conditional()->endFrontals(); it++) {
149  originalValues[it - clique->conditional()->beginFrontals()] = delta[*it];
150  }
151 
152  // Back-substitute - special version stores solution pointers in cliques for fast access.
153  {
154  // Create solution part pointers if necessary and possible - necessary if solnPointers_ is
155  // empty, and possible if either we're a root, or we have a parent with valid solnPointers_.
156  boost::shared_ptr<CLIQUE> parent = clique->parent_.lock();
157  if(clique->solnPointers_.empty() && (clique->isRoot() || !parent->solnPointers_.empty()))
158  {
159  BOOST_FOREACH(Key key, clique->conditional()->frontals())
160  clique->solnPointers_.insert(std::make_pair(key, delta.find(key)));
161  BOOST_FOREACH(Key key, clique->conditional()->parents())
162  clique->solnPointers_.insert(std::make_pair(key, parent->solnPointers_.at(key)));
163  }
164 
165  // See if we can use solution part pointers - we can if they either already existed or were
166  // created above.
167  if(!clique->solnPointers_.empty())
168  {
169  GaussianConditional& c = *clique->conditional();
170  // Solve matrix
171  Vector xS;
172  {
173  // Count dimensions of vector
174  DenseIndex dim = 0;
175  FastVector<VectorValues::const_iterator> parentPointers;
176  parentPointers.reserve(clique->conditional()->nrParents());
177  BOOST_FOREACH(Key parent, clique->conditional()->parents()) {
178  parentPointers.push_back(clique->solnPointers_.at(parent));
179  dim += parentPointers.back()->second.size();
180  }
181 
182  // Fill parent vector
183  xS.resize(dim);
184  DenseIndex vectorPos = 0;
185  BOOST_FOREACH(const VectorValues::const_iterator& parentPointer, parentPointers) {
186  const Vector& parentVector = parentPointer->second;
187  xS.block(vectorPos,0,parentVector.size(),1) = parentVector.block(0,0,parentVector.size(),1);
188  vectorPos += parentVector.size();
189  }
190  }
191  xS = c.getb() - c.get_S() * xS;
192  Vector soln = c.get_R().triangularView<Eigen::Upper>().solve(xS);
193 
194  // Check for indeterminant solution
195  if(soln.hasNaN()) throw IndeterminantLinearSystemException(c.keys().front());
196 
197  // Insert solution into a VectorValues
198  DenseIndex vectorPosition = 0;
199  for(GaussianConditional::const_iterator frontal = c.beginFrontals(); frontal != c.endFrontals(); ++frontal) {
200  clique->solnPointers_.at(*frontal)->second = soln.segment(vectorPosition, c.getDim(frontal));
201  vectorPosition += c.getDim(frontal);
202  }
203  }
204  else
205  {
206  // Just call plain solve because we couldn't use solution pointers.
207  delta.update(clique->conditional()->solve(delta));
208  }
209  }
210  count += clique->conditional()->nrFrontals();
211 
212  // Whether the values changed above a threshold, or always true if the
213  // clique was replaced.
214  bool valuesChanged = cliqueReplaced;
215  for(it = clique->conditional()->beginFrontals(); it != clique->conditional()->endFrontals(); it++) {
216  if(!valuesChanged) {
217  const Vector& oldValue(originalValues[it - clique->conditional()->beginFrontals()]);
218  const Vector& newValue(delta[*it]);
219  if((oldValue - newValue).lpNorm<Eigen::Infinity>() >= threshold) {
220  valuesChanged = true;
221  break;
222  }
223  } else
224  break;
225  }
226 
227  // If the values were above the threshold or this clique was replaced
228  if(valuesChanged) {
229  // Set changed flag for each frontal variable and leave the new values
230  BOOST_FOREACH(Key frontal, clique->conditional()->frontals()) {
231  changed.insert(frontal);
232  }
233  } else {
234  // Replace with the old values
235  for(it = clique->conditional()->beginFrontals(); it != clique->conditional()->endFrontals(); it++) {
236  delta[*it] = originalValues[it - clique->conditional()->beginFrontals()];
237  }
238  }
239  }
240 
241  return recalculate;
242 }
243 
244 } // namespace internal
245 
246 /* ************************************************************************* */
247 template<class CLIQUE>
248 size_t optimizeWildfire(const boost::shared_ptr<CLIQUE>& root, double threshold, const FastSet<Key>& keys, VectorValues& delta) {
249  FastSet<Key> changed;
250  int count = 0;
251  // starting from the root, call optimize on each conditional
252  if(root)
253  internal::optimizeWildfire(root, threshold, changed, keys, delta, count);
254  return count;
255 }
256 
257 /* ************************************************************************* */
258 template<class CLIQUE>
259 size_t optimizeWildfireNonRecursive(const boost::shared_ptr<CLIQUE>& root, double threshold, const FastSet<Key>& keys, VectorValues& delta)
260 {
261  FastSet<Key> changed;
262  size_t count = 0;
263 
264  if (root) {
265  std::stack<boost::shared_ptr<CLIQUE> > travStack;
266  travStack.push(root);
267  boost::shared_ptr<CLIQUE> currentNode = root;
268  while (!travStack.empty()) {
269  currentNode = travStack.top();
270  travStack.pop();
271  bool recalculate = internal::optimizeWildfireNode(currentNode, threshold, changed, keys, delta, count);
272  if (recalculate) {
273  BOOST_FOREACH(const typename CLIQUE::shared_ptr& child, currentNode->children) {
274  travStack.push(child);
275  }
276  }
277  }
278  }
279 
280  return count;
281 }
282 
283 /* ************************************************************************* */
284 template<class CLIQUE>
285 void nnz_internal(const boost::shared_ptr<CLIQUE>& clique, int& result) {
286  int dimR = (int)clique->conditional()->rows();
287  int dimSep = (int)clique->conditional()->get_S().cols();
288  result += ((dimR+1)*dimR)/2 + dimSep*dimR;
289  // traverse the children
290  BOOST_FOREACH(const typename CLIQUE::shared_ptr& child, clique->children) {
291  nnz_internal(child, result);
292  }
293 }
294 
295 /* ************************************************************************* */
296 template<class CLIQUE>
297 int calculate_nnz(const boost::shared_ptr<CLIQUE>& clique) {
298  int result = 0;
299  // starting from the root, add up entries of frontal and conditional matrices of each conditional
300  nnz_internal(clique, result);
301  return result;
302 }
303 
304 }
305 
306 
Values calculateEstimate() const
Compute an estimate from the incomplete linear delta computed during the last update.
Definition: ISAM2.cpp:1016
void solve(Matrix &A, Matrix &B)
solve AX=B via in-place Lu factorization and backsubstitution After calling, A contains LU...
Definition: Matrix.cpp:283
bool exists(const VALUE &e) const
Handy 'exists' function.
Definition: FastSet.h:98
Values::const_iterator const_iterator
Const iterator over vector values.
Definition: VectorValues.h:97
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:70
size_t dim(const Vector &v)
dimensionality == size
Definition: Vector.h:90
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:297
const ValueType & at(Key j) const
Retrieve a variable by key j.
Definition: Values-inl.h:219
size_t optimizeWildfire(const boost::shared_ptr< CLIQUE > &root, double threshold, const FastSet< Key > &keys, VectorValues &delta)
Optimize the BayesTree, starting from the root.
Definition: ISAM2-inl.h:248
size_t Key
Integer nonlinear key type.
Definition: types.h:59
ptrdiff_t DenseIndex
The index type for Eigen objects.
Definition: types.h:74
This class represents a collection of vector-valued variables associated each with a unique integer i...
Definition: VectorValues.h:89
Values theta_
The current linearization point.
Definition: ISAM2.h:429
Vector delta(size_t n, size_t i, double value)
Create basis vector of dimension n, with a constant in spot i.
Definition: Vector.cpp:53
const VectorValues & getDelta() const
Access the current delta, computed during the last call to update.
Definition: ISAM2.cpp:1042
FastVector< Key >::const_iterator const_iterator
Const iterator over keys.
Definition: Factor.h:64
Factor Graph Base Class.