24 REGULAR_COUT << YELLOW_START <<
"HolisticFusion: OptimizerLMBatch" << GREEN_START
25 <<
" Initializing slow batch smoother that is optimized with LM." << COLOR_END << std::endl;
27 if (graphConfigPtr_->slowBatchSmootherUseCholeskyFactorizationFlag_) {
28 lmParams_.linearSolverType = gtsam::NonlinearOptimizerParams::MULTIFRONTAL_CHOLESKY;
29 REGULAR_COUT <<
"Using Multifrontal-Cholesky factorization for slow batch smoother (LM)." << std::endl;
31 lmParams_.linearSolverType = gtsam::NonlinearOptimizerParams::MULTIFRONTAL_QR;
32 REGULAR_COUT <<
"Using Multifrontal-QR factorization for slow batch smoother (LM)." << std::endl;
35 lmParams_.print(
"HolisticFusion: OptimizerLMBatch, LM Parameters:");
175 gtsam::NonlinearFactorGraph filteredGraph;
176 int numFilteredFactors = 0;
177 for (
const auto& factor : graph) {
178 bool foundKeyInFactor =
false;
179 for (
const gtsam::Key& key : factor->keys()) {
180 if (key == keyToFilter) {
181 foundKeyInFactor =
true;
185 if (!foundKeyInFactor) {
186 filteredGraph.add(factor);
188 numFilteredFactors++;
191 graph = filteredGraph;
192 return numFilteredFactors;
195 static gtsam::Marginals
computeMarginals(gtsam::NonlinearFactorGraph& graph, gtsam::Values& values) {
200 gtsam::Marginals marginals;
202 marginals = gtsam::Marginals(graph, values);
203 }
catch (
const gtsam::IndeterminateSystemException& e) {
204 std::cout <<
"HolisticFusion: OptimizerLMBatch: computing marginals failed with error: " << e.what() << std::endl;
206 std::cout <<
"HolisticFusion: OptimizerLMBatch: filtering out ill-conditioned state: " << gtsam::Symbol(e.nearbyVariable()) << std::endl;
208 bool foundInValues =
false;
209 for (
const gtsam::Key& key : values.keys()) {
210 if (key == e.nearbyVariable()) {
212 foundInValues =
true;
221 std::cout <<
"HolisticFusion: OptimizerLMBatch: Filtered out state from values (" << gtsam::Symbol(e.nearbyVariable()) <<
")."
223 std::cout <<
"HolisticFusion: OptimizerLMBatch: Filtered out " << numFilteredFactors <<
" factors. Retrying to compute marginals."
228 throw std::runtime_error(
"HolisticFusion: OptimizerLMBatch: computing marginals failed and could not filter out ill-conditioned state.");
230 }
catch (
const gtsam::ValuesKeyDoesNotExist& e) {
231 std::cout <<
"HolisticFusion: OptimizerLMBatch: computing marginals failed with error: " << e.what() << std::endl;
235 std::cout <<
"HolisticFusion: OptimizerLMBatch: Filtered out " << numFilteredFactors <<
" factors. Retrying to compute marginals."
248 throw std::runtime_error(
"HolisticFusion: OptimizerLMBatch: computeAndStoreAllMarginals: No optimization has been performed yet.");
255 std::sort(keysSorted.begin(), keysSorted.end(), [&](
const gtsam::Key& key1,
const gtsam::Key& key2) {
256 return batchSmootherKeyTimestampMap_.at(key1) < batchSmootherKeyTimestampMap_.at(key2);
262 int numKeys = keysSorted.size();
263 double timeDifference = endTime - startTime;
266 std::cout <<
"HolisticFusion: OptimizerLMBatch: Graph consisting of " << numKeys <<
" keys is spanning " << timeDifference <<
" seconds."
270 const double& windowSizeSeconds =
graphConfigPtr_->windowSizeSecondsForMarginalsComputation_;
271 int numSubGraphs = std::ceil(timeDifference / windowSizeSeconds);
272 std::cout <<
"HolisticFusion: OptimizerLMBatch: Dividing graph into " << numSubGraphs <<
" main windows." << std::endl;
273 numSubGraphs += (numSubGraphs - 1);
274 std::cout <<
"HolisticFusion: OptimizerLMBatch: Dividing graph into " << numSubGraphs
275 <<
" overlapping windows (to make sure there are no edges)." << std::endl;
278 std::vector<double> subGraphCenterTimes;
280 std::vector<double> subGraphStartTimes;
281 std::vector<double> subGraphEndTimes;
284 if (numSubGraphs > 1) {
286 subGraphCenterTimes =
linspace(startTime + windowSizeSeconds / 2, endTime - windowSizeSeconds / 2, numSubGraphs);
287 for (
int i = 0; i < numSubGraphs; ++i) {
288 subGraphStartTimes.push_back(subGraphCenterTimes[i] - windowSizeSeconds / 2);
289 subGraphEndTimes.push_back(subGraphCenterTimes[i] + windowSizeSeconds / 2);
294 subGraphCenterTimes.push_back((startTime + endTime) / 2);
295 subGraphStartTimes.push_back(startTime);
296 subGraphEndTimes.push_back(endTime);
300 for (
int i = 0; i < numSubGraphs; ++i) {
301 std::cout <<
"Subgraph " << i <<
" starts at relative " << subGraphStartTimes[i] - startTime <<
" seconds and ends at relative "
302 << subGraphEndTimes[i] - startTime <<
" seconds." << std::endl;
303 std::cout <<
"Center time: " << subGraphCenterTimes[i] - startTime <<
" seconds." << std::endl;
318 bool factorAtLeastInOneSubGraph =
false;
320 for (
int i = 0; i < numSubGraphs; ++i) {
322 int numReferenceFrameKeysInFactor = 0;
323 for (
const auto& factorKey : factorPtr->keys()) {
326 if (gtsam::Symbol(factorKey).chr() ==
'r') {
327 numReferenceFrameKeysInFactor++;
328 if (numReferenceFrameKeysInFactor == 1) {
330 }
else if (numReferenceFrameKeysInFactor > 1) {
331 std::cout <<
"Found random walk factor with (at least) two reference frame keys (including " << gtsam::Symbol(factorKey)
332 <<
")." << std::endl;
340 factorAtLeastInOneSubGraph =
true;
346 if (!factorAtLeastInOneSubGraph) {
347 throw std::runtime_error(
"HolisticFusion: OptimizerLMBatch: Factor does not contain any key within the time window of any sub-graph.");
352 for (
const auto& key : keysSorted) {
355 double minTimeDifference = std::numeric_limits<double>::max();
356 int closestSubGraphIndex = -1;
358 for (
int i = 0; i < numSubGraphs; ++i) {
359 const double timeDifference = std::abs(subGraphCenterTimes[i] - keyTime);
360 if (timeDifference < minTimeDifference) {
361 minTimeDifference = timeDifference;
362 closestSubGraphIndex = i;
370 for (
int i = 0; i < numSubGraphs; ++i) {
372 std::cout <<
"HolisticFusion: OptimizerLMBatch: Optimizing subgraph " << i <<
" with " <<
subGraphs_[i].size() <<
" factors and "
373 <<
subGraphs_[i].keys().size() <<
" keys." << std::endl;
377 std::cout <<
"HolisticFusion: OptimizerLMBatch: Subgraph " << i <<
" optimized and marginals computed." << std::endl;
384 std::cout <<
"HolisticFusion: OptimizerLMBatch: Divided graph into subgraphs." << std::endl;