-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathMRISAM2.h
235 lines (190 loc) · 9.03 KB
/
MRISAM2.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#pragma once
#include "MRBayesTree.h"
#include <gtsam/nonlinear/NonlinearFactorGraph.h>
namespace gtsam {
struct MRISAM2Params {
GaussianFactorGraph::Eliminate eliminate_function;
double relinearization_threshold = 0.1;
double delta_update_threshold = 0.1;
double marginal_update_threshold = 0.1;
bool show_details = false;
bool marginal_change_use_gradient = true;
MRISAM2Params(const GaussianFactorGraph::Eliminate _eliminate_function =
EliminateCholesky)
: eliminate_function(_eliminate_function) {}
};
struct MRISAM2Result;
/**
* @brief Implementation of the full multi-root ISAM2 algorithm for multi-robot
* incremental nonlinear optimization.
*/
class MRISAM2 : public MRBayesTree<GaussianBayesTree, GaussianFactorGraph> {
public:
typedef MRBayesTree<GaussianBayesTree, GaussianFactorGraph> MRBT;
MRISAM2() : MRBT(), params_(MRISAM2Params()) {}
/** constructor
* @param graph nonlinear factor graph
* @param values values of variables
* @param order elimination order to create the tree
* @param root_id this root id
* @param other_root_keys_map map from root_id to keys in other roots
* @param params mrisam2 params
*/
MRISAM2(const NonlinearFactorGraph& graph, const Values& values,
const Ordering& order, const RootID root_id,
const RootKeySetMap& other_root_keys_map,
const MRISAM2Params& params = MRISAM2Params())
: MRISAM2(graph, *graph.linearize(values), values, order, root_id, other_root_keys_map,
params) {}
MRISAM2(const NonlinearFactorGraph& nonlinear_factors,
const GaussianFactorGraph& linear_factors, const Values& values,
const Ordering& order, const RootID root_id,
const RootKeySetMap& other_root_keys_map,
const MRISAM2Params& params)
: MRBT(linear_factors, order, root_id, other_root_keys_map, false,
params.eliminate_function),
params_(params),
nonlinear_factors_(nonlinear_factors),
linear_factors_(linear_factors),
variable_index_(VariableIndex(linear_factors)),
theta_(values),
delta_(values.zeroVectors())
{
SharedClique root_clique = roots_.begin()->second;
computeDelta(root_clique, root_clique, linear_factors_, variable_index_, delta_);
}
/** mark cliques that has any of specified keys as frontal variables, or
* include relinearized variables, and all cliques on the path from such
* cliques to root
* @param root_id specified root
* @param involved_keys keys involved in new factors
* @param relin_keys keys to relinearize
* @return set of marked cliques
*/
CliqueSet markCliques(const SharedClique root_clique,
const KeySet& involved_keys,
const KeySet& relin_keys) const;
/** remove top at corresponding root, and return the factor graph and orphans
* @param root_id specified root
* @param top_cliques the cliques to remove
* @param top_factor_indices (return) indices of factors in top
* @param top_keys (return) keys ONLY in top of tree
* @return the edges cut (points toward orphans)
*/
EdgeVector extractTop(const SharedClique root_clique,
const CliqueSet& top_cliques,
FactorIndices& top_factor_indices,
KeySet& top_keys) const;
/** connect orphans to the new top
* @param root_id specified root
* @param new_top_mrbt newly created top part of tree
* @param orphan_edges old edges connecting to orphan subtrees
*/
EdgeVector connectOrphans(const RootID root_id, MRBT& new_top_mrbt,
const EdgeVector& orphan_edges);
static Key findMostRecentStateKey(const RootID root_id, const SharedClique& root_clique);
/** recreate the top part of the tree by re-eliminating the factor graph
* (Note: the marginals, conditionals and deltas for the newly created cliques
* and edges are not computed)
* @param root_id specified root
* @param old_top_cliques cliques in old top tree
* @param top_graph the new factors corresponding to the new top graph
* @param orphan_edges old edges connecting to orphan subtrees
* @param new_factor_keys keys associated with newly added factors
* @return new edges connected to orphans
*/
EdgeVector recreateTop(const RootID root_id, CliqueSet& old_top_cliques,
const FactorIndices& top_factor_indices,
const EdgeVector& orphan_edges,
const KeySet& new_factor_keys,
MRISAM2Result& update_result);
/** perform elimination in top part of the tree, set the marginals,
* conditionals and deltas in top. (Note: for the boundary edges pointing
* toward top, the marginals are not computed)
* @param root_id specified root
* @param boundary_edges new edges created to connect orphans (point in the
* direction toward orphans)
*/
void eliminateTop(const RootID root_id, const EdgeVector& boundary_edges);
double marginalChangeByGradient(const SharedFactor& old_marginal, const SharedFactor& new_marginal) const;
double marginalChangeByKLD(const SharedFactor& old_marginal, const SharedFactor& new_marginal) const;
/** compare two marginals by their KL Divergence */
bool marginalChanged(const SharedFactor& old_marginal,
const SharedFactor& new_marginal) const;
void propagateDeltaRecursive(const SharedEdge& edge, MRISAM2Result& update_result);
void propagateMarginalsRecursive(const SharedEdge& edge, MRISAM2Result& update_result);
/** propagate marginals outside from the top tree
* @param root_id specified root
* @param boundary_edges new edges created to connect orphans (point in the
* direction toward orphans)
*/
void propagateMarginals(const RootID root_id,
const EdgeVector& boundary_edges,
MRISAM2Result& update_result);
/** compute delta with a wildfire spread from the boundary edges */
void propagateDeltas(const RootID root_id, const EdgeVector& boundary_edges,
MRISAM2Result& update_result);
// VectorValues computeEstimates(const RootID root_id,
// const CliqueSet& top_cliques);
/** check the condition of inputs are correct: root id should be valid; new
* values should be provided for all new appeared variables, while no other
* variables are included */
void updateRootCheck(const RootID root_id,
const NonlinearFactorGraph& new_factors,
const Values& new_theta);
/** update at a root with new factors and new values
* @param root_id specified root
* @param new_factors new measurements gathered by the robot
* @param new_theta initial estimate for new variables
* @param do_relinearization perform relinearization in this update step
*/
MRISAM2Result updateRoot(const RootID root_id, const NonlinearFactorGraph& new_factors,
const Values& new_theta, const bool do_relinearization = false);
/** recursively find the keys that need relinearization
* @param parent parent clique
* @param clique current clique
* @param relin_keys (return) keys to be relinearized
*/
void checkRelinearizationRecursive(const SharedClique& parent,
const SharedClique& clique,
KeySet& relin_keys) const;
/** gather keys that need relinearization */
KeySet gatherRelinearizeKeys(const SharedClique& root_clique) const;
/** gather existing keys involved in new factors */
KeySet gatherInvolvedKeys(const NonlinearFactorGraph& new_factors) const;
/** relinearize factors in top */
void relinearizeTop(const KeySet& top_keys,
const FactorIndices& top_factor_indices);
void addVariables(const Values& new_theta);
FactorIndices addFactors(const NonlinearFactorGraph& new_factors);
const NonlinearFactorGraph& nonlinearFactors() {return nonlinear_factors_; }
const GaussianFactorGraph& linearFactors() {return linear_factors_; }
const VariableIndex& variableIndex() {return variable_index_; }
const Values& theta() {return theta_; }
const VectorValues& delta() {return delta_; }
MRISAM2Params& params() {return params_; }
Values calculateBestEstimate();
protected:
MRISAM2Params params_;
NonlinearFactorGraph nonlinear_factors_;
GaussianFactorGraph linear_factors_;
VariableIndex variable_index_;
Values theta_;
VectorValues delta_;
};
struct MRISAM2Result {
KeySet top_keys;
FactorIndices top_factor_indices;
KeySet relin_keys;
KeySet involved_keys;
size_t old_top_clique_size = 0;
size_t new_top_clique_size = 0;
size_t propagated_delta = 0;
size_t propagated_marginal = 0;
std::set<size_t> roots_in_top;
std::vector<double> durations;
size_t largest_clique_size;
KeySet variables_reeliminated;
MRISAM2::CliqueSet top_cliques;
};
} // namespace gtsam